@woopsy/mcpanel 2.1.3 ā 2.1.5
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/dist/commands/commandRouter.js +7 -1
- package/dist/index.js +52 -19
- package/dist/managers/playitManager.js +16 -0
- package/dist/utils/logger.js +4 -0
- package/package.json +1 -1
|
@@ -69,7 +69,7 @@ class CommandRouter {
|
|
|
69
69
|
' /stop - Stop the server gracefully',
|
|
70
70
|
' /restart - Restart the server',
|
|
71
71
|
' /console - Enter the interactive server console',
|
|
72
|
-
' /log -
|
|
72
|
+
' /log - Stream live server logs in this terminal (read-only)',
|
|
73
73
|
' /info - Show server path, type, version and status',
|
|
74
74
|
' /sync <path> - Connect a different server folder',
|
|
75
75
|
' /properties - Edit server.properties interactively',
|
|
@@ -79,6 +79,7 @@ class CommandRouter {
|
|
|
79
79
|
' /tunnel java - Auto-create & start a Java tunnel, returns address',
|
|
80
80
|
' /tunnel bedrock - Auto-create & start a Bedrock tunnel, returns address',
|
|
81
81
|
' /tunnel status - Check tunnel status, address and latency',
|
|
82
|
+
' /tunnel log - Stream live playit relay logs in this terminal (read-only)',
|
|
82
83
|
' /tunnel stop - Stop the playit tunnel agent',
|
|
83
84
|
' /tunnel reset - Clear saved agent secret (re-claim on next tunnel)',
|
|
84
85
|
'',
|
|
@@ -430,6 +431,7 @@ class CommandRouter {
|
|
|
430
431
|
}
|
|
431
432
|
if (status.address && status.address !== 'None') {
|
|
432
433
|
output.push(`\nš® Connect at: ${colors.bold(colors.green(`${status.address}:${status.port}`))}`);
|
|
434
|
+
output.push(colors.gray(`(Enter the full address WITH ":${status.port}" ā the bare domain defaults to 25565 and won't connect.)`));
|
|
433
435
|
}
|
|
434
436
|
// Persistence diagnostics: whether the agent is claimed/saved, and where.
|
|
435
437
|
// If this says "Not saved", /tunnel will re-claim a new agent every run.
|
|
@@ -528,9 +530,13 @@ class CommandRouter {
|
|
|
528
530
|
},
|
|
529
531
|
onStatus: (msg) => console.log(colors.info(msg)),
|
|
530
532
|
});
|
|
533
|
+
const portHint = type === 'java'
|
|
534
|
+
? colors.gray(`In Minecraft, enter the FULL address including ":${status.port}" ā the bare domain defaults to port 25565 and will not connect.`)
|
|
535
|
+
: colors.gray(`In Minecraft Bedrock, enter the address and set the Port field to ${status.port}.`);
|
|
531
536
|
return [
|
|
532
537
|
colors.success(`${type === 'java' ? 'Java' : 'Bedrock'} tunnel is online!`),
|
|
533
538
|
`\nš® Connect at: ${colors.bold(colors.green(`${status.address}:${status.port}`))}`,
|
|
539
|
+
portHint,
|
|
534
540
|
colors.gray('Share this address with players. The tunnel stays up while MCPANEL is running.'),
|
|
535
541
|
].join('\n');
|
|
536
542
|
}
|
package/dist/index.js
CHANGED
|
@@ -169,12 +169,12 @@ const COMMAND_LIST = [
|
|
|
169
169
|
'/backup create', '/backup list', '/backup restore',
|
|
170
170
|
'/plugins list', '/plugins install', '/plugins remove',
|
|
171
171
|
'/setup',
|
|
172
|
-
'/tunnel java', '/tunnel bedrock', '/tunnel status', '/tunnel stop', '/tunnel reset',
|
|
172
|
+
'/tunnel java', '/tunnel bedrock', '/tunnel status', '/tunnel log', '/tunnel stop', '/tunnel reset',
|
|
173
173
|
'/config', '/clear', '/update', '/tray', '/background', '/exit'
|
|
174
174
|
];
|
|
175
175
|
// Subcommands offered once "<command> " has been typed.
|
|
176
176
|
const SUBCOMMANDS = {
|
|
177
|
-
'/tunnel': ['java', 'bedrock', 'status', 'stop', 'reset'],
|
|
177
|
+
'/tunnel': ['java', 'bedrock', 'status', 'log', 'stop', 'reset'],
|
|
178
178
|
'/backup': ['create', 'list', 'restore'],
|
|
179
179
|
'/plugins': ['list', 'install', 'remove'],
|
|
180
180
|
};
|
|
@@ -287,6 +287,17 @@ function exitLogView() {
|
|
|
287
287
|
console.log(colors.info('\nReturned to MCPANEL shell.'));
|
|
288
288
|
promptUser();
|
|
289
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Exits the in-place live tunnel-log view.
|
|
292
|
+
*/
|
|
293
|
+
function exitTunnelLogView() {
|
|
294
|
+
if (currentState !== 'TUNNEL_LOG_VIEW')
|
|
295
|
+
return;
|
|
296
|
+
playitManager.unregisterTunnelStream();
|
|
297
|
+
currentState = 'COMMAND';
|
|
298
|
+
console.log(colors.info('\nReturned to MCPANEL shell.'));
|
|
299
|
+
promptUser();
|
|
300
|
+
}
|
|
290
301
|
/**
|
|
291
302
|
* Prompt loop builder
|
|
292
303
|
*/
|
|
@@ -313,7 +324,7 @@ function promptUser() {
|
|
|
313
324
|
rl.setPrompt(colors.bold(`Enter new value for ${propertiesContext.selectedKey}: `));
|
|
314
325
|
rl.prompt();
|
|
315
326
|
}
|
|
316
|
-
else if (currentState === 'CONSOLE' || currentState === 'LOG_VIEW') {
|
|
327
|
+
else if (currentState === 'CONSOLE' || currentState === 'LOG_VIEW' || currentState === 'TUNNEL_LOG_VIEW') {
|
|
317
328
|
// Log/console streaming has no custom prompt.
|
|
318
329
|
rl.setPrompt('');
|
|
319
330
|
}
|
|
@@ -393,8 +404,8 @@ function enterConsoleMode() {
|
|
|
393
404
|
});
|
|
394
405
|
}
|
|
395
406
|
/**
|
|
396
|
-
* /log ā
|
|
397
|
-
*
|
|
407
|
+
* /log ā streams live server logs read-only inside THIS terminal (like
|
|
408
|
+
* /console, but without sending commands). Type /back or /exit to return.
|
|
398
409
|
*/
|
|
399
410
|
function handleLogCommand() {
|
|
400
411
|
const server = configManager.getServer();
|
|
@@ -403,7 +414,6 @@ function handleLogCommand() {
|
|
|
403
414
|
return;
|
|
404
415
|
}
|
|
405
416
|
const logPath = logger_1.logger.getServerLogPath(server.name);
|
|
406
|
-
// Ensure the file exists so `tail -f` has something to follow.
|
|
407
417
|
if (!fs.existsSync(logPath)) {
|
|
408
418
|
try {
|
|
409
419
|
fs.writeFileSync(logPath, '', 'utf-8');
|
|
@@ -411,27 +421,41 @@ function handleLogCommand() {
|
|
|
411
421
|
catch { /* ignore */ }
|
|
412
422
|
}
|
|
413
423
|
const running = !!processManager.getActiveServer(server.name);
|
|
414
|
-
const opened = (0, helpers_1.openTerminalTail)(logPath, `MCPANEL Logs - ${server.name}`);
|
|
415
|
-
if (opened) {
|
|
416
|
-
console.log(colors.success('Live server logs opened in a new terminal window.'));
|
|
417
|
-
if (!running) {
|
|
418
|
-
console.log(colors.warning('Server is not running yet ā log lines will appear once you /start it.'));
|
|
419
|
-
}
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
// Fallback: stream the logs read-only inside this shell.
|
|
423
|
-
console.log(colors.warning('Could not open a separate terminal window ā showing logs here instead.'));
|
|
424
424
|
logViewServer = server.name;
|
|
425
425
|
currentState = 'LOG_VIEW';
|
|
426
|
-
console.log(colors.bold(colors.magenta(`\n--- Live Logs: ${server.name}
|
|
426
|
+
console.log(colors.bold(colors.magenta(`\n--- Live Server Logs: ${server.name} ---`)));
|
|
427
|
+
console.log(colors.gray('Read-only. Type /back or /exit to return to MCPANEL shell.\n'));
|
|
427
428
|
if (fs.existsSync(logPath)) {
|
|
428
429
|
const logs = fs.readFileSync(logPath, 'utf-8').split('\n');
|
|
429
430
|
process.stdout.write(logs.slice(-30).join('\n') + '\n');
|
|
430
431
|
}
|
|
432
|
+
if (!running) {
|
|
433
|
+
console.log(colors.warning('Server is not running yet ā lines will appear once you /start it.'));
|
|
434
|
+
}
|
|
431
435
|
processManager.registerConsoleStream(server.name, (data) => {
|
|
432
436
|
process.stdout.write(data);
|
|
433
437
|
});
|
|
434
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* /tunnel log ā streams the live playit relay log read-only in THIS terminal.
|
|
441
|
+
* Seeds from tunnel.log, then follows the running relay's output. /back to exit.
|
|
442
|
+
*/
|
|
443
|
+
function enterTunnelLogView() {
|
|
444
|
+
const logPath = logger_1.logger.getTunnelLogPath();
|
|
445
|
+
currentState = 'TUNNEL_LOG_VIEW';
|
|
446
|
+
console.log(colors.bold(colors.magenta('\n--- Live Tunnel Logs (playit relay) ---')));
|
|
447
|
+
console.log(colors.gray('Read-only. Type /back or /exit to return to MCPANEL shell.\n'));
|
|
448
|
+
if (fs.existsSync(logPath)) {
|
|
449
|
+
const logs = fs.readFileSync(logPath, 'utf-8').split('\n');
|
|
450
|
+
process.stdout.write(logs.slice(-30).join('\n') + '\n');
|
|
451
|
+
}
|
|
452
|
+
if (!playitManager.isAgentRunning()) {
|
|
453
|
+
console.log(colors.warning('Tunnel agent is not running ā start it with /tunnel java or /tunnel bedrock.'));
|
|
454
|
+
}
|
|
455
|
+
playitManager.registerTunnelStream((data) => {
|
|
456
|
+
process.stdout.write(data);
|
|
457
|
+
});
|
|
458
|
+
}
|
|
435
459
|
/**
|
|
436
460
|
* Command line loop orchestrator
|
|
437
461
|
*/
|
|
@@ -531,6 +555,12 @@ async function handleLine(line) {
|
|
|
531
555
|
exitLogView();
|
|
532
556
|
}
|
|
533
557
|
break;
|
|
558
|
+
case 'TUNNEL_LOG_VIEW':
|
|
559
|
+
// Read-only: only /back or /exit leaves; everything else is ignored.
|
|
560
|
+
if (trimmed === '/exit' || trimmed === '/back') {
|
|
561
|
+
exitTunnelLogView();
|
|
562
|
+
}
|
|
563
|
+
break;
|
|
534
564
|
}
|
|
535
565
|
}
|
|
536
566
|
/**
|
|
@@ -688,7 +718,7 @@ async function handleCommandState(line) {
|
|
|
688
718
|
case '/tunnel': {
|
|
689
719
|
const sub = (args[0] || '').toLowerCase();
|
|
690
720
|
if (!sub) {
|
|
691
|
-
console.log(colors.failure('Syntax: /tunnel [java|bedrock|status|stop|reset]'));
|
|
721
|
+
console.log(colors.failure('Syntax: /tunnel [java|bedrock|status|log|stop|reset]'));
|
|
692
722
|
}
|
|
693
723
|
else if (sub === 'java' || sub === 'bedrock') {
|
|
694
724
|
console.log(await router.executeTunnelCreate(sub));
|
|
@@ -708,11 +738,14 @@ async function handleCommandState(line) {
|
|
|
708
738
|
else if (sub === 'status') {
|
|
709
739
|
console.log(router.executeTunnelStatus());
|
|
710
740
|
}
|
|
741
|
+
else if (sub === 'log') {
|
|
742
|
+
enterTunnelLogView();
|
|
743
|
+
}
|
|
711
744
|
else if (sub === 'reset') {
|
|
712
745
|
console.log(await router.executeTunnelReset());
|
|
713
746
|
}
|
|
714
747
|
else {
|
|
715
|
-
console.log(colors.failure('Syntax: /tunnel [java|bedrock|status|stop|reset]'));
|
|
748
|
+
console.log(colors.failure('Syntax: /tunnel [java|bedrock|status|log|stop|reset]'));
|
|
716
749
|
}
|
|
717
750
|
break;
|
|
718
751
|
}
|
|
@@ -58,6 +58,8 @@ class PlayitManager {
|
|
|
58
58
|
playitProcess = null;
|
|
59
59
|
claimProcess = null;
|
|
60
60
|
tunnelStatus;
|
|
61
|
+
// Optional live consumer of relay output, used by the inline `/tunnel log` view.
|
|
62
|
+
tunnelLogCallback = null;
|
|
61
63
|
constructor(configManager) {
|
|
62
64
|
this.configManager = configManager;
|
|
63
65
|
this.tunnelStatus = this.offlineStatus();
|
|
@@ -456,11 +458,13 @@ class PlayitManager {
|
|
|
456
458
|
const chunk = stripAnsi(d.toString());
|
|
457
459
|
logger_1.logger.logTunnel(`[stdout] ${chunk.trim()}`);
|
|
458
460
|
this.parsePlayitOutput(chunk);
|
|
461
|
+
this.tunnelLogCallback?.(chunk);
|
|
459
462
|
});
|
|
460
463
|
this.playitProcess.stderr?.on('data', (d) => {
|
|
461
464
|
const chunk = stripAnsi(d.toString());
|
|
462
465
|
logger_1.logger.logTunnel(`[stderr] ${chunk.trim()}`);
|
|
463
466
|
this.parsePlayitOutput(chunk);
|
|
467
|
+
this.tunnelLogCallback?.(chunk);
|
|
464
468
|
});
|
|
465
469
|
this.playitProcess.on('close', (code) => {
|
|
466
470
|
logger_1.logger.logTunnel(`Playit relay exited with code ${code}`);
|
|
@@ -502,6 +506,18 @@ class PlayitManager {
|
|
|
502
506
|
getStatus() {
|
|
503
507
|
return this.tunnelStatus;
|
|
504
508
|
}
|
|
509
|
+
/** True when the relay daemon process is currently running. */
|
|
510
|
+
isAgentRunning() {
|
|
511
|
+
return this.playitProcess !== null;
|
|
512
|
+
}
|
|
513
|
+
/** Streams live relay output (stdout/stderr) to the given consumer. */
|
|
514
|
+
registerTunnelStream(cb) {
|
|
515
|
+
this.tunnelLogCallback = cb;
|
|
516
|
+
}
|
|
517
|
+
/** Stops streaming live relay output. */
|
|
518
|
+
unregisterTunnelStream() {
|
|
519
|
+
this.tunnelLogCallback = null;
|
|
520
|
+
}
|
|
505
521
|
/** Clears the saved secret so the agent can be re-claimed from scratch. */
|
|
506
522
|
async resetSecret() {
|
|
507
523
|
this.stopTunnel();
|
package/dist/utils/logger.js
CHANGED
|
@@ -77,6 +77,10 @@ exports.logger = {
|
|
|
77
77
|
// Return path to the runtime console log for the server
|
|
78
78
|
return path.join(LOGS_DIR, `server-${serverName.toLowerCase()}.log`);
|
|
79
79
|
},
|
|
80
|
+
getTunnelLogPath() {
|
|
81
|
+
ensureLogsDirExists();
|
|
82
|
+
return path.join(LOGS_DIR, 'tunnel.log');
|
|
83
|
+
},
|
|
80
84
|
writeServerConsoleLog(serverName, data) {
|
|
81
85
|
ensureLogsDirExists();
|
|
82
86
|
const filePath = path.join(LOGS_DIR, `server-${serverName.toLowerCase()}.log`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@woopsy/mcpanel",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "MCPANEL ā a terminal-based, single-server Minecraft server manager with an Arch/neofetch-style UI, live logs, backups, plugins and Playit.gg tunnels.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|