UNPKG

onepm-mcp

Version:

Complete onepm integration for Cursor IDE - Get tasks, manage features, track time, and build features with AI. Supports both MCP stdio mode and HTTP server mode. Enhanced task management with improved ID handling for seamless workflow.

361 lines (303 loc) • 10.9 kB
#!/usr/bin/env node /** * onepm MCP Task Management Script * * This script helps manage pending tasks that are found during polling. * It provides an interactive way to approve, reject, or list tasks. */ const axios = require('axios'); const readline = require('readline'); const MCP_SERVER_URL = process.env.MCP_SERVER_URL || 'http://localhost:3002'; class TaskManager { constructor(serverUrl) { this.serverUrl = serverUrl; this.rl = readline.createInterface({ input: process.stdin, output: process.stdout }); } async makeRequest(endpoint, method = 'GET', data = null) { try { const config = { method, url: `${this.serverUrl}${endpoint}`, headers: { 'Content-Type': 'application/json' } }; if (data) { config.data = data; } const response = await axios(config); return response.data; } catch (error) { if (error.response) { throw new Error(`HTTP ${error.response.status}: ${error.response.data?.error || error.message}`); } throw new Error(`Network error: ${error.message}`); } } async getPendingTasks() { console.log('šŸ“‹ Getting pending tasks...'); try { const response = await this.makeRequest('/polling/pending-tasks'); return response.pendingTasks || []; } catch (error) { if (error.message.includes('404')) { console.log('ā„¹ļø No pending tasks endpoint found - this is expected in older versions'); return []; } throw error; } } async getPollingStatus() { console.log('šŸ“Š Getting polling status...'); const status = await this.makeRequest('/polling/status'); return status; } async approveTask(taskId) { console.log(`āœ… Approving task: ${taskId}`); const result = await this.makeRequest(`/polling/approve-task/${taskId}`, 'POST'); console.log(`āœ… ${result.message}`); return result; } async approveAllTasks() { console.log('āœ… Approving all pending tasks...'); const result = await this.makeRequest('/polling/approve-all-tasks', 'POST'); console.log(`āœ… ${result.message}`); return result; } async rejectTask(taskId) { console.log(`āŒ Rejecting task: ${taskId}`); const result = await this.makeRequest(`/polling/reject-task/${taskId}`, 'POST'); console.log(`āŒ ${result.message}`); return result; } async stopPolling() { console.log('ā¹ļø Stopping polling...'); const result = await this.makeRequest('/polling/stop', 'POST'); console.log(`ā¹ļø ${result.message}`); return result; } async startPolling() { console.log('ā–¶ļø Starting polling...'); const result = await this.makeRequest('/polling/start', 'POST'); console.log(`ā–¶ļø ${result.message}`); return result; } async restartPolling() { console.log('šŸ”„ Restarting polling...'); const result = await this.makeRequest('/polling/restart', 'POST'); console.log(`šŸ”„ ${result.message}`); return result; } displayTasks(tasks) { if (tasks.length === 0) { console.log('šŸ“­ No pending tasks found'); return; } console.log(`\nšŸ“‹ Found ${tasks.length} pending task(s):\n`); tasks.forEach((task, index) => { console.log(`${index + 1}. šŸŽÆ ${task.featureId}`); console.log(` šŸ“ Requirements: ${task.requirements.substring(0, 80)}${task.requirements.length > 80 ? '...' : ''}`); console.log(` šŸ·ļø Product: ${task.product}`); console.log(` ā±ļø Estimated Hours: ${task.estimatedHours}`); console.log(` šŸ†” ID: ${task.id}`); console.log(''); }); } async interactiveMode() { console.log('šŸŽ›ļø onepm MCP Task Manager - Interactive Mode\n'); while (true) { try { // Get current status const status = await this.getPollingStatus(); const tasks = await this.getPendingTasks(); console.log('\nšŸ“Š Current Status:'); console.log(` Polling Active: ${status.isPolling ? 'āœ… Yes' : 'āŒ No'}`); console.log(` Currently Processing: ${status.currentlyProcessingTasks || 0}`); console.log(` Pending Tasks: ${tasks.length}`); console.log(` Processed Requests: ${status.processedRequestsCount || 0}`); this.displayTasks(tasks); console.log('šŸ’” Available Commands:'); console.log(' list - List pending tasks'); console.log(' approve - Approve a specific task'); console.log(' approve-all - Approve all pending tasks'); console.log(' reject - Reject a specific task'); console.log(' stop - Stop polling'); console.log(' start - Start polling'); console.log(' restart - Restart polling'); console.log(' status - Show detailed status'); console.log(' quit - Exit interactive mode'); const command = await this.question('\nEnter command: ').then(cmd => cmd.trim().toLowerCase()); switch (command) { case 'list': this.displayTasks(tasks); break; case 'approve': if (tasks.length === 0) { console.log('āŒ No tasks to approve'); break; } const taskIndex = await this.question(`Enter task number (1-${tasks.length}): `).then(num => parseInt(num) - 1); if (taskIndex >= 0 && taskIndex < tasks.length) { await this.approveTask(tasks[taskIndex].id); } else { console.log('āŒ Invalid task number'); } break; case 'approve-all': if (tasks.length === 0) { console.log('āŒ No tasks to approve'); break; } const confirm = await this.question(`Are you sure you want to approve all ${tasks.length} tasks? (y/N): `); if (confirm.toLowerCase() === 'y' || confirm.toLowerCase() === 'yes') { await this.approveAllTasks(); } else { console.log('āŒ Approval cancelled'); } break; case 'reject': if (tasks.length === 0) { console.log('āŒ No tasks to reject'); break; } const rejectIndex = await this.question(`Enter task number to reject (1-${tasks.length}): `).then(num => parseInt(num) - 1); if (rejectIndex >= 0 && rejectIndex < tasks.length) { await this.rejectTask(tasks[rejectIndex].id); } else { console.log('āŒ Invalid task number'); } break; case 'stop': await this.stopPolling(); break; case 'start': await this.startPolling(); break; case 'restart': await this.restartPolling(); break; case 'status': console.log('\nšŸ“Š Detailed Status:'); console.log(JSON.stringify(status, null, 2)); break; case 'quit': case 'exit': console.log('šŸ‘‹ Goodbye!'); this.rl.close(); return; default: console.log('āŒ Unknown command. Type "quit" to exit.'); } // Wait a moment before showing the menu again await new Promise(resolve => setTimeout(resolve, 1000)); } catch (error) { console.error('āŒ Error:', error.message); await new Promise(resolve => setTimeout(resolve, 2000)); } } } question(prompt) { return new Promise((resolve) => { this.rl.question(prompt, resolve); }); } close() { this.rl.close(); } } async function main() { const command = process.argv[2]; const manager = new TaskManager(MCP_SERVER_URL); try { switch (command) { case 'interactive': case 'i': await manager.interactiveMode(); break; case 'list': const tasks = await manager.getPendingTasks(); manager.displayTasks(tasks); break; case 'approve': const taskId = process.argv[3]; if (!taskId) { console.error('āŒ Task ID required: node manage-tasks.js approve <taskId>'); process.exit(1); } await manager.approveTask(taskId); break; case 'approve-all': await manager.approveAllTasks(); break; case 'reject': const rejectTaskId = process.argv[3]; if (!rejectTaskId) { console.error('āŒ Task ID required: node manage-tasks.js reject <taskId>'); process.exit(1); } await manager.rejectTask(rejectTaskId); break; case 'status': const status = await manager.getPollingStatus(); console.log('\nšŸ“Š Polling Status:'); console.log(JSON.stringify(status, null, 2)); break; case 'stop': await manager.stopPolling(); break; case 'start': await manager.startPolling(); break; case 'restart': await manager.restartPolling(); break; case 'help': case '--help': case '-h': console.log(` šŸŽ›ļø onepm MCP Task Manager Usage: node manage-tasks.js <command> [options] Commands: interactive, i - Start interactive mode (recommended) list - List pending tasks approve <id> - Approve a specific task approve-all - Approve all pending tasks reject <id> - Reject a specific task status - Show polling status stop - Stop polling start - Start polling restart - Restart polling help - Show this help message Environment Variables: MCP_SERVER_URL - MCP server URL (default: http://localhost:3002) Examples: node manage-tasks.js interactive node manage-tasks.js list node manage-tasks.js approve abc123 node manage-tasks.js approve-all MCP_SERVER_URL=http://localhost:3003 node manage-tasks.js status `); break; default: console.error(`āŒ Unknown command: ${command}`); console.log('Run "node manage-tasks.js help" for usage information'); process.exit(1); } } catch (error) { console.error(`āŒ Error: ${error.message}`); if (error.code === 'ECONNREFUSED') { console.log('\nšŸ’” Make sure the MCP server is running:'); console.log(' npx onepm-mcp start --http-server'); } process.exit(1); } finally { manager.close(); } } if (require.main === module) { main(); } module.exports = TaskManager;