@yeaft/webchat-agent 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/service.js +102 -122
package/package.json
CHANGED
package/service.js
CHANGED
|
@@ -371,80 +371,87 @@ function macLogs() {
|
|
|
371
371
|
// ─── Windows (Task Scheduler) ────────────────────────────────
|
|
372
372
|
|
|
373
373
|
const WIN_TASK_NAME = 'YeaftAgent';
|
|
374
|
+
const PM2_APP_NAME = 'yeaft-agent';
|
|
374
375
|
|
|
375
|
-
|
|
376
|
-
|
|
376
|
+
// Legacy paths for cleanup
|
|
377
|
+
function getWinWrapperPath() { return join(getConfigDir(), 'run.vbs'); }
|
|
378
|
+
function getWinBatPath() { return join(getConfigDir(), 'run.bat'); }
|
|
379
|
+
|
|
380
|
+
function ensurePm2() {
|
|
381
|
+
try {
|
|
382
|
+
execSync('pm2 --version', { stdio: 'pipe' });
|
|
383
|
+
} catch {
|
|
384
|
+
console.log('Installing pm2...');
|
|
385
|
+
execSync('npm install -g pm2', { stdio: 'inherit' });
|
|
386
|
+
}
|
|
377
387
|
}
|
|
378
388
|
|
|
379
|
-
function
|
|
380
|
-
return join(getConfigDir(), '
|
|
389
|
+
function getEcosystemPath() {
|
|
390
|
+
return join(getConfigDir(), 'ecosystem.config.cjs');
|
|
381
391
|
}
|
|
382
392
|
|
|
383
|
-
function
|
|
393
|
+
function generateEcosystem(config) {
|
|
384
394
|
const nodePath = getNodePath();
|
|
385
395
|
const cliPath = getCliPath();
|
|
396
|
+
const cliDir = dirname(cliPath);
|
|
386
397
|
const logDir = getLogDir();
|
|
387
398
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
if (config.
|
|
391
|
-
if (config.
|
|
392
|
-
if (config.
|
|
393
|
-
|
|
399
|
+
const env = {};
|
|
400
|
+
if (config.serverUrl) env.SERVER_URL = config.serverUrl;
|
|
401
|
+
if (config.agentName) env.AGENT_NAME = config.agentName;
|
|
402
|
+
if (config.agentSecret) env.AGENT_SECRET = config.agentSecret;
|
|
403
|
+
if (config.workDir) env.WORK_DIR = config.workDir;
|
|
404
|
+
|
|
405
|
+
return `module.exports = {
|
|
406
|
+
apps: [{
|
|
407
|
+
name: '${PM2_APP_NAME}',
|
|
408
|
+
script: '${cliPath.replace(/\\/g, '\\\\')}',
|
|
409
|
+
interpreter: '${nodePath.replace(/\\/g, '\\\\')}',
|
|
410
|
+
cwd: '${cliDir.replace(/\\/g, '\\\\')}',
|
|
411
|
+
env: ${JSON.stringify(env, null, 6)},
|
|
412
|
+
autorestart: true,
|
|
413
|
+
watch: false,
|
|
414
|
+
max_restarts: 10,
|
|
415
|
+
restart_delay: 5000,
|
|
416
|
+
log_date_format: 'YYYY-MM-DD HH:mm:ss',
|
|
417
|
+
error_file: '${join(logDir, 'error.log').replace(/\\/g, '\\\\')}',
|
|
418
|
+
out_file: '${join(logDir, 'out.log').replace(/\\/g, '\\\\')}',
|
|
419
|
+
merge_logs: true,
|
|
420
|
+
max_memory_restart: '500M',
|
|
421
|
+
}]
|
|
422
|
+
};
|
|
423
|
+
`;
|
|
424
|
+
}
|
|
394
425
|
|
|
395
|
-
|
|
426
|
+
function winInstall(config) {
|
|
427
|
+
ensurePm2();
|
|
428
|
+
const logDir = getLogDir();
|
|
396
429
|
mkdirSync(logDir, { recursive: true });
|
|
397
|
-
const logFile = join(logDir, 'out.log');
|
|
398
|
-
const cliDir = dirname(cliPath);
|
|
399
|
-
const batContent = `@echo off\r\ncd /d "${cliDir}"\r\n${envLines.join('\r\n')}\r\n"${nodePath}" "${cliPath}" >> "${logFile}" 2>&1\r\n`;
|
|
400
|
-
const batPath = getWinBatPath();
|
|
401
|
-
writeFileSync(batPath, batContent);
|
|
402
430
|
|
|
403
|
-
//
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
writeFileSync(vbsPath, vbsContent);
|
|
431
|
+
// Generate ecosystem config
|
|
432
|
+
const ecoPath = getEcosystemPath();
|
|
433
|
+
writeFileSync(ecoPath, generateEcosystem(config));
|
|
407
434
|
|
|
408
|
-
//
|
|
409
|
-
try { execSync(`
|
|
435
|
+
// Stop existing instance if any
|
|
436
|
+
try { execSync(`pm2 delete ${PM2_APP_NAME}`, { stdio: 'pipe' }); } catch {}
|
|
410
437
|
|
|
411
|
-
//
|
|
412
|
-
|
|
413
|
-
let usedStartupFolder = false;
|
|
414
|
-
try {
|
|
415
|
-
execSync(
|
|
416
|
-
`schtasks /create /tn "${WIN_TASK_NAME}" /tr "wscript.exe \\"${vbsPath}\\"" /sc onlogon /rl highest /f`,
|
|
417
|
-
{ stdio: 'pipe' }
|
|
418
|
-
);
|
|
419
|
-
} catch {
|
|
420
|
-
try {
|
|
421
|
-
execSync(
|
|
422
|
-
`schtasks /create /tn "${WIN_TASK_NAME}" /tr "wscript.exe \\"${vbsPath}\\"" /sc onlogon /rl limited /f`,
|
|
423
|
-
{ stdio: 'pipe' }
|
|
424
|
-
);
|
|
425
|
-
} catch {
|
|
426
|
-
// schtasks not available (no admin) — use Startup folder
|
|
427
|
-
const startupDir = join(process.env.APPDATA, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');
|
|
428
|
-
const startupVbs = join(startupDir, `${WIN_TASK_NAME}.vbs`);
|
|
429
|
-
writeFileSync(startupVbs, vbsContent);
|
|
430
|
-
usedStartupFolder = true;
|
|
431
|
-
console.log(' (Using Startup folder for auto-start — no admin required)');
|
|
432
|
-
}
|
|
433
|
-
}
|
|
438
|
+
// Start with pm2
|
|
439
|
+
execSync(`pm2 start "${ecoPath}"`, { stdio: 'inherit' });
|
|
434
440
|
|
|
435
|
-
//
|
|
436
|
-
|
|
437
|
-
execSync(`wscript.exe "${vbsPath}"`, { stdio: 'pipe' });
|
|
438
|
-
} else {
|
|
439
|
-
execSync(`schtasks /run /tn "${WIN_TASK_NAME}"`, { stdio: 'pipe' });
|
|
440
|
-
}
|
|
441
|
+
// Save pm2 process list for resurrection
|
|
442
|
+
execSync('pm2 save', { stdio: 'pipe' });
|
|
441
443
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
444
|
+
// Setup auto-start: create startup script in Windows Startup folder
|
|
445
|
+
// pm2-startup doesn't work well on Windows, use Startup folder approach
|
|
446
|
+
const startupDir = join(process.env.APPDATA, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');
|
|
447
|
+
const startupBat = join(startupDir, `${PM2_APP_NAME}.bat`);
|
|
448
|
+
// pm2 is in PATH (ensured by ensurePm2), so just call it directly
|
|
449
|
+
const batContent = `@echo off\r\npm2 resurrect\r\n`;
|
|
450
|
+
writeFileSync(startupBat, batContent);
|
|
451
|
+
|
|
452
|
+
console.log(`\nService installed and started.`);
|
|
453
|
+
console.log(` Ecosystem: ${ecoPath}`);
|
|
454
|
+
console.log(` Startup: ${startupBat}`);
|
|
448
455
|
console.log(`\nManage with:`);
|
|
449
456
|
console.log(` yeaft-agent status`);
|
|
450
457
|
console.log(` yeaft-agent logs`);
|
|
@@ -453,14 +460,19 @@ function winInstall(config) {
|
|
|
453
460
|
}
|
|
454
461
|
|
|
455
462
|
function winUninstall() {
|
|
456
|
-
try {
|
|
457
|
-
try { execSync(
|
|
458
|
-
// Clean up
|
|
463
|
+
try { execSync(`pm2 delete ${PM2_APP_NAME}`, { stdio: 'pipe' }); } catch {}
|
|
464
|
+
try { execSync('pm2 save', { stdio: 'pipe' }); } catch {}
|
|
465
|
+
// Clean up ecosystem config
|
|
466
|
+
const ecoPath = getEcosystemPath();
|
|
467
|
+
if (existsSync(ecoPath)) unlinkSync(ecoPath);
|
|
468
|
+
// Clean up Startup bat
|
|
469
|
+
const startupBat = join(process.env.APPDATA, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', `${PM2_APP_NAME}.bat`);
|
|
470
|
+
if (existsSync(startupBat)) unlinkSync(startupBat);
|
|
471
|
+
// Clean up legacy files
|
|
459
472
|
const vbsPath = getWinWrapperPath();
|
|
460
473
|
const batPath = getWinBatPath();
|
|
461
474
|
if (existsSync(vbsPath)) unlinkSync(vbsPath);
|
|
462
475
|
if (existsSync(batPath)) unlinkSync(batPath);
|
|
463
|
-
// Clean up Startup folder shortcut
|
|
464
476
|
const startupVbs = join(process.env.APPDATA, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', `${WIN_TASK_NAME}.vbs`);
|
|
465
477
|
if (existsSync(startupVbs)) unlinkSync(startupVbs);
|
|
466
478
|
console.log('Service uninstalled.');
|
|
@@ -468,14 +480,12 @@ function winUninstall() {
|
|
|
468
480
|
|
|
469
481
|
function winStart() {
|
|
470
482
|
try {
|
|
471
|
-
execSync(`
|
|
472
|
-
console.log('Service started.');
|
|
483
|
+
execSync(`pm2 start ${PM2_APP_NAME}`, { stdio: 'inherit' });
|
|
473
484
|
} catch {
|
|
474
|
-
//
|
|
475
|
-
const
|
|
476
|
-
if (existsSync(
|
|
477
|
-
execSync(`
|
|
478
|
-
console.log('Service started.');
|
|
485
|
+
// Try ecosystem file
|
|
486
|
+
const ecoPath = getEcosystemPath();
|
|
487
|
+
if (existsSync(ecoPath)) {
|
|
488
|
+
execSync(`pm2 start "${ecoPath}"`, { stdio: 'inherit' });
|
|
479
489
|
} else {
|
|
480
490
|
console.error('Service not installed. Run "yeaft-agent install" first.');
|
|
481
491
|
process.exit(1);
|
|
@@ -484,73 +494,43 @@ function winStart() {
|
|
|
484
494
|
}
|
|
485
495
|
|
|
486
496
|
function winStop() {
|
|
487
|
-
// Find and kill the node process running our cli.js
|
|
488
497
|
try {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
for (const line of output.split('\n')) {
|
|
494
|
-
if (line.includes('cli.js') && (line.includes(SERVICE_NAME) || line.includes('webchat-agent'))) {
|
|
495
|
-
const pid = line.trim().split(',').pop();
|
|
496
|
-
if (pid && /^\d+$/.test(pid)) {
|
|
497
|
-
execSync(`taskkill /pid ${pid} /f`, { stdio: 'pipe' });
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
} catch {}
|
|
502
|
-
// Also try to end the task
|
|
503
|
-
try { execSync(`schtasks /end /tn "${WIN_TASK_NAME}"`, { stdio: 'pipe' }); } catch {}
|
|
504
|
-
console.log('Service stopped.');
|
|
498
|
+
execSync(`pm2 stop ${PM2_APP_NAME}`, { stdio: 'inherit' });
|
|
499
|
+
} catch {
|
|
500
|
+
console.error('Service not running or not installed.');
|
|
501
|
+
}
|
|
505
502
|
}
|
|
506
503
|
|
|
507
504
|
function winRestart() {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
505
|
+
try {
|
|
506
|
+
execSync(`pm2 restart ${PM2_APP_NAME}`, { stdio: 'inherit' });
|
|
507
|
+
} catch {
|
|
508
|
+
console.error('Service not running. Use "yeaft-agent start" to start.');
|
|
509
|
+
}
|
|
512
510
|
}
|
|
513
511
|
|
|
514
512
|
function winStatus() {
|
|
515
513
|
try {
|
|
516
|
-
|
|
517
|
-
encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe']
|
|
518
|
-
});
|
|
519
|
-
const lines = output.trim().split('\n');
|
|
520
|
-
if (lines.length >= 2) {
|
|
521
|
-
// Parse CSV header + data
|
|
522
|
-
const headers = lines[0].split('","').map(h => h.replace(/"/g, ''));
|
|
523
|
-
const values = lines[1].split('","').map(v => v.replace(/"/g, ''));
|
|
524
|
-
const statusIdx = headers.indexOf('Status');
|
|
525
|
-
const status = statusIdx >= 0 ? values[statusIdx] : 'Unknown';
|
|
526
|
-
console.log(`Service status: ${status}`);
|
|
527
|
-
console.log(`Task name: ${WIN_TASK_NAME}`);
|
|
528
|
-
}
|
|
514
|
+
execSync(`pm2 describe ${PM2_APP_NAME}`, { stdio: 'inherit' });
|
|
529
515
|
} catch {
|
|
530
|
-
|
|
531
|
-
const startupVbs = join(process.env.APPDATA, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', `${WIN_TASK_NAME}.vbs`);
|
|
532
|
-
if (existsSync(startupVbs)) {
|
|
533
|
-
console.log('Service installed via Startup folder (no admin).');
|
|
534
|
-
console.log(`Startup script: ${startupVbs}`);
|
|
535
|
-
} else {
|
|
536
|
-
console.log('Service is not installed.');
|
|
537
|
-
}
|
|
516
|
+
console.log('Service is not installed.');
|
|
538
517
|
}
|
|
539
518
|
}
|
|
540
519
|
|
|
541
520
|
function winLogs() {
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
521
|
+
const child = spawn('pm2', ['logs', PM2_APP_NAME, '--lines', '100'], {
|
|
522
|
+
stdio: 'inherit',
|
|
523
|
+
shell: true
|
|
524
|
+
});
|
|
525
|
+
child.on('error', () => {
|
|
526
|
+
// Fallback to reading log file directly
|
|
527
|
+
const logFile = join(getLogDir(), 'out.log');
|
|
528
|
+
if (existsSync(logFile)) {
|
|
549
529
|
console.log(readFileSync(logFile, 'utf-8'));
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
530
|
+
} else {
|
|
531
|
+
console.log('No logs found.');
|
|
532
|
+
}
|
|
533
|
+
});
|
|
554
534
|
}
|
|
555
535
|
|
|
556
536
|
// ─── Platform dispatcher ─────────────────────────────────────
|