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
JavaScript
/**
* 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;