@koodosbots/kprcli
Version:
KprCli - Global CLI automation client for Telegram bot integration
295 lines (253 loc) ⢠8.07 kB
JavaScript
/**
* KprCli - Ultra Simple CLI Client
* Zero dependencies, single file solution
*/
const http = require('http');
const https = require('https');
const readline = require('readline');
const os = require('os');
// Default config
const CONFIG = {
botUrl: 'http://localhost:3333',
version: '1.0.0'
};
// Colors for terminal output
const colors = {
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
reset: '\x1b[0m'
};
function log(message, color = 'white') {
console.log(colors[color] + message + colors.reset);
}
function makeRequest(url, options = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const client = urlObj.protocol === 'https:' ? https : http;
const req = client.request(url, options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
const json = JSON.parse(data);
resolve({ status: res.statusCode, data: json });
} catch (e) {
resolve({ status: res.statusCode, data: data });
}
});
});
req.on('error', reject);
if (options.body) {
req.write(options.body);
}
req.end();
});
}
function askQuestion(question) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise(resolve => {
rl.question(question, answer => {
rl.close();
resolve(answer);
});
});
}
async function login() {
log('\nš¤ KprCli Login', 'cyan');
log('===============', 'cyan');
log('\n1. Go to your Telegram bot and run /link', 'white');
log('2. Copy the 6-digit code from Telegram\n', 'white');
const authCode = await askQuestion('Enter authentication code: ');
if (!authCode.match(/^[A-F0-9]{6}$/)) {
log('ā Invalid code format. Expected 6 uppercase hex characters (e.g., ABC123)', 'red');
process.exit(1);
}
log(`š Authenticating with code: ${authCode}`, 'yellow');
try {
const response = await makeRequest(`${CONFIG.botUrl}/api/cli/auth`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
authCode: authCode,
deviceInfo: {
hostname: os.hostname(),
platform: os.platform(),
version: CONFIG.version
}
})
});
if (response.status === 200 && response.data.success) {
log('ā
Device authenticated successfully!', 'green');
log(`š± Device ID: ${response.data.deviceId}`, 'blue');
log(`š Access Token: ${response.data.accessToken.substring(0, 16)}...`, 'blue');
// Save credentials to file
require('fs').writeFileSync('.kprcli-config', JSON.stringify({
deviceId: response.data.deviceId,
accessToken: response.data.accessToken,
botUrl: CONFIG.botUrl
}));
log('š¾ Credentials saved to .kprcli-config', 'green');
log('\nRun: kprcli start', 'cyan');
} else {
log('ā Authentication failed: ' + (response.data.error || 'Unknown error'), 'red');
process.exit(1);
}
} catch (error) {
log('ā Connection error: ' + error.message, 'red');
process.exit(1);
}
}
async function start() {
// Load credentials
let config;
try {
const configFile = require('fs').readFileSync('.kprcli-config', 'utf8');
config = JSON.parse(configFile);
} catch (e) {
log('ā No configuration found. Please run: kprcli login', 'red');
process.exit(1);
}
log('\nš KprCli Agent Starting...', 'green');
log(`š± Device: ${config.deviceId.substring(0, 8)}...`, 'blue');
log('š Polling for jobs every 5 seconds', 'yellow');
log('Press Ctrl+C to stop\n', 'white');
let pollCount = 0;
const poll = async () => {
try {
const response = await makeRequest(`${config.botUrl}/api/cli/jobs/${config.deviceId}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${config.accessToken}`
}
});
if (response.status === 200) {
pollCount++;
const jobs = response.data.jobs || [];
if (jobs.length > 0) {
log(`š¬ Found ${jobs.length} job(s):`, 'green');
jobs.forEach(job => {
log(` ⢠Job ID: ${job.id}`, 'white');
log(` ⢠Task: ${job.taskType}`, 'white');
log(` ⢠Status: ${job.status}`, 'white');
// Execute job after 2 seconds
setTimeout(() => executeJob(config, job), 2000);
});
} else {
if (pollCount % 12 === 0) { // Show every minute (12 * 5 seconds)
log(`š” Polling... (${pollCount} checks, ${Math.floor(pollCount * 5 / 60)} min)`, 'blue');
}
}
}
} catch (error) {
log('ā Polling error: ' + error.message, 'red');
}
};
// Poll every 5 seconds
const interval = setInterval(poll, 5000);
// Handle Ctrl+C
process.on('SIGINT', () => {
clearInterval(interval);
log('\nš Stopping KprCli agent...', 'yellow');
process.exit(0);
});
// Start polling immediately
poll();
}
async function executeJob(config, job) {
log(`ā” Executing job: ${job.id}...`, 'yellow');
// Simulate work for 1-3 seconds
const workTime = Math.random() * 2000 + 1000;
await new Promise(resolve => setTimeout(resolve, workTime));
try {
const response = await makeRequest(`${config.botUrl}/api/cli/jobs/${job.id}/complete`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
success: true,
result: `Task completed successfully by ${os.hostname()}`,
error: null
})
});
if (response.status === 200) {
log(`ā
Job ${job.id.substring(0, 8)}... completed successfully`, 'green');
} else {
log(`ā Failed to report job completion`, 'red');
}
} catch (error) {
log('ā Job completion error: ' + error.message, 'red');
}
}
function showHelp() {
log('\nš¤ KprCli - Simple Automation Client', 'cyan');
log('=====================================', 'cyan');
log('\nCommands:', 'white');
log(' kprcli login - Link device to Telegram bot', 'green');
log(' kprcli start - Start automation agent', 'green');
log(' kprcli status - Show device status', 'green');
log(' kprcli help - Show this help', 'green');
log('\nUsage:', 'white');
log(' 1. Run "kprcli login" first', 'yellow');
log(' 2. Enter auth code from Telegram bot', 'yellow');
log(' 3. Run "kprcli start" to begin automation\n', 'yellow');
}
function showStatus() {
try {
const configFile = require('fs').readFileSync('.kprcli-config', 'utf8');
const config = JSON.parse(configFile);
log('\nš KprCli Status', 'cyan');
log('================', 'cyan');
log(`Device ID: ${config.deviceId}`, 'blue');
log(`Bot URL: ${config.botUrl}`, 'blue');
log(`Token: ${config.accessToken.substring(0, 16)}...`, 'blue');
log('Status: Configured ā
', 'green');
log('\nRun: kprcli start', 'yellow');
} catch (e) {
log('\nš KprCli Status', 'cyan');
log('================', 'cyan');
log('Status: Not configured ā', 'red');
log('Run: kprcli login', 'yellow');
}
}
// Main CLI handler
function main() {
const args = process.argv.slice(2);
const command = args[0] || 'help';
switch (command) {
case 'login':
login();
break;
case 'start':
start();
break;
case 'status':
showStatus();
break;
case 'help':
case '--help':
case '-h':
showHelp();
break;
default:
log(`ā Unknown command: ${command}`, 'red');
showHelp();
break;
}
}
// Run if called directly
if (require.main === module) {
main();
}
module.exports = { main };