@minecraft-docker/mcctl 1.6.0 → 1.6.2
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/application/index.d.ts +2 -0
- package/dist/application/index.d.ts.map +1 -0
- package/dist/application/index.js +5 -0
- package/dist/application/index.js.map +1 -0
- package/dist/commands/backup.d.ts +16 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +182 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/ban.d.ts +14 -0
- package/dist/commands/ban.d.ts.map +1 -0
- package/dist/commands/ban.js +418 -0
- package/dist/commands/ban.js.map +1 -0
- package/dist/commands/config.d.ts +18 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +106 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/console/api.d.ts +19 -0
- package/dist/commands/console/api.d.ts.map +1 -0
- package/dist/commands/console/api.js +399 -0
- package/dist/commands/console/api.js.map +1 -0
- package/dist/commands/console/index.d.ts +10 -0
- package/dist/commands/console/index.d.ts.map +1 -0
- package/dist/commands/console/index.js +12 -0
- package/dist/commands/console/index.js.map +1 -0
- package/dist/commands/console/init.d.ts +47 -0
- package/dist/commands/console/init.d.ts.map +1 -0
- package/dist/commands/console/init.js +491 -0
- package/dist/commands/console/init.js.map +1 -0
- package/dist/commands/console/remove.d.ts +25 -0
- package/dist/commands/console/remove.d.ts.map +1 -0
- package/dist/commands/console/remove.js +189 -0
- package/dist/commands/console/remove.js.map +1 -0
- package/dist/commands/console/service.d.ts +40 -0
- package/dist/commands/console/service.d.ts.map +1 -0
- package/dist/commands/console/service.js +321 -0
- package/dist/commands/console/service.js.map +1 -0
- package/dist/commands/console/user.d.ts +17 -0
- package/dist/commands/console/user.d.ts.map +1 -0
- package/dist/commands/console/user.js +431 -0
- package/dist/commands/console/user.js.map +1 -0
- package/dist/commands/create.d.ts +22 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +86 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/delete.d.ts +17 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +74 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/exec.d.ts +10 -0
- package/dist/commands/exec.d.ts.map +1 -0
- package/dist/commands/exec.js +29 -0
- package/dist/commands/exec.js.map +1 -0
- package/dist/commands/index.d.ts +21 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +23 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +218 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/kick.d.ts +12 -0
- package/dist/commands/kick.d.ts.map +1 -0
- package/dist/commands/kick.js +71 -0
- package/dist/commands/kick.js.map +1 -0
- package/dist/commands/migrate.d.ts +18 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +470 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/mod.d.ts +19 -0
- package/dist/commands/mod.d.ts.map +1 -0
- package/dist/commands/mod.js +441 -0
- package/dist/commands/mod.js.map +1 -0
- package/dist/commands/msg.d.ts +12 -0
- package/dist/commands/msg.d.ts.map +1 -0
- package/dist/commands/msg.js +273 -0
- package/dist/commands/msg.js.map +1 -0
- package/dist/commands/op.d.ts +12 -0
- package/dist/commands/op.d.ts.map +1 -0
- package/dist/commands/op.js +220 -0
- package/dist/commands/op.js.map +1 -0
- package/dist/commands/player-online.d.ts +11 -0
- package/dist/commands/player-online.d.ts.map +1 -0
- package/dist/commands/player-online.js +153 -0
- package/dist/commands/player-online.js.map +1 -0
- package/dist/commands/player.d.ts +18 -0
- package/dist/commands/player.d.ts.map +1 -0
- package/dist/commands/player.js +352 -0
- package/dist/commands/player.js.map +1 -0
- package/dist/commands/server-backup.d.ts +36 -0
- package/dist/commands/server-backup.d.ts.map +1 -0
- package/dist/commands/server-backup.js +320 -0
- package/dist/commands/server-backup.js.map +1 -0
- package/dist/commands/server-restore.d.ts +13 -0
- package/dist/commands/server-restore.d.ts.map +1 -0
- package/dist/commands/server-restore.js +294 -0
- package/dist/commands/server-restore.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +325 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/whitelist.d.ts +12 -0
- package/dist/commands/whitelist.d.ts.map +1 -0
- package/dist/commands/whitelist.js +316 -0
- package/dist/commands/whitelist.js.map +1 -0
- package/dist/commands/world.d.ts +18 -0
- package/dist/commands/world.d.ts.map +1 -0
- package/dist/commands/world.js +238 -0
- package/dist/commands/world.js.map +1 -0
- package/dist/domain/index.d.ts +2 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +7 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +766 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/adapters/ClackPromptAdapter.d.ts +30 -0
- package/dist/infrastructure/adapters/ClackPromptAdapter.d.ts.map +1 -0
- package/dist/infrastructure/adapters/ClackPromptAdapter.js +430 -0
- package/dist/infrastructure/adapters/ClackPromptAdapter.js.map +1 -0
- package/dist/infrastructure/adapters/Pm2ServiceManagerAdapter.d.ts +78 -0
- package/dist/infrastructure/adapters/Pm2ServiceManagerAdapter.d.ts.map +1 -0
- package/dist/infrastructure/adapters/Pm2ServiceManagerAdapter.js +391 -0
- package/dist/infrastructure/adapters/Pm2ServiceManagerAdapter.js.map +1 -0
- package/dist/infrastructure/adapters/index.d.ts +4 -0
- package/dist/infrastructure/adapters/index.d.ts.map +1 -0
- package/dist/infrastructure/adapters/index.js +6 -0
- package/dist/infrastructure/adapters/index.js.map +1 -0
- package/dist/infrastructure/di/container.d.ts +47 -0
- package/dist/infrastructure/di/container.d.ts.map +1 -0
- package/dist/infrastructure/di/container.js +140 -0
- package/dist/infrastructure/di/container.js.map +1 -0
- package/dist/infrastructure/di/index.d.ts +2 -0
- package/dist/infrastructure/di/index.d.ts.map +1 -0
- package/dist/infrastructure/di/index.js +2 -0
- package/dist/infrastructure/di/index.js.map +1 -0
- package/dist/infrastructure/index.d.ts +5 -0
- package/dist/infrastructure/index.d.ts.map +1 -0
- package/dist/infrastructure/index.js +8 -0
- package/dist/infrastructure/index.js.map +1 -0
- package/dist/lib/admin-config.d.ts +66 -0
- package/dist/lib/admin-config.d.ts.map +1 -0
- package/dist/lib/admin-config.js +130 -0
- package/dist/lib/admin-config.js.map +1 -0
- package/dist/lib/mojang-api.d.ts +51 -0
- package/dist/lib/mojang-api.d.ts.map +1 -0
- package/dist/lib/mojang-api.js +136 -0
- package/dist/lib/mojang-api.js.map +1 -0
- package/dist/lib/player-cache.d.ts +79 -0
- package/dist/lib/player-cache.d.ts.map +1 -0
- package/dist/lib/player-cache.js +302 -0
- package/dist/lib/player-cache.js.map +1 -0
- package/dist/lib/player-json.d.ts +69 -0
- package/dist/lib/player-json.d.ts.map +1 -0
- package/dist/lib/player-json.js +96 -0
- package/dist/lib/player-json.js.map +1 -0
- package/dist/lib/pm2-utils.d.ts +71 -0
- package/dist/lib/pm2-utils.d.ts.map +1 -0
- package/dist/lib/pm2-utils.js +155 -0
- package/dist/lib/pm2-utils.js.map +1 -0
- package/dist/lib/prompts/action-select.d.ts +23 -0
- package/dist/lib/prompts/action-select.d.ts.map +1 -0
- package/dist/lib/prompts/action-select.js +124 -0
- package/dist/lib/prompts/action-select.js.map +1 -0
- package/dist/lib/prompts/index.d.ts +7 -0
- package/dist/lib/prompts/index.d.ts.map +1 -0
- package/dist/lib/prompts/index.js +7 -0
- package/dist/lib/prompts/index.js.map +1 -0
- package/dist/lib/prompts/ip-select.d.ts +25 -0
- package/dist/lib/prompts/ip-select.d.ts.map +1 -0
- package/dist/lib/prompts/ip-select.js +255 -0
- package/dist/lib/prompts/ip-select.js.map +1 -0
- package/dist/lib/prompts/player-select.d.ts +25 -0
- package/dist/lib/prompts/player-select.d.ts.map +1 -0
- package/dist/lib/prompts/player-select.js +122 -0
- package/dist/lib/prompts/player-select.js.map +1 -0
- package/dist/lib/prompts/server-select.d.ts +26 -0
- package/dist/lib/prompts/server-select.d.ts.map +1 -0
- package/dist/lib/prompts/server-select.js +99 -0
- package/dist/lib/prompts/server-select.js.map +1 -0
- package/dist/lib/rcon.d.ts +53 -0
- package/dist/lib/rcon.d.ts.map +1 -0
- package/dist/lib/rcon.js +131 -0
- package/dist/lib/rcon.js.map +1 -0
- package/dist/lib/shell.d.ts +111 -0
- package/dist/lib/shell.d.ts.map +1 -0
- package/dist/lib/shell.js +321 -0
- package/dist/lib/shell.js.map +1 -0
- package/dist/lib/sudo-utils.d.ts +14 -0
- package/dist/lib/sudo-utils.d.ts.map +1 -0
- package/dist/lib/sudo-utils.js +53 -0
- package/dist/lib/sudo-utils.js.map +1 -0
- package/package.json +8 -2
package/dist/index.js
ADDED
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Paths, log, colors } from '@minecraft-docker/shared';
|
|
3
|
+
import { initCommand, statusCommand, createCommand, deleteCommand, worldCommand, backupCommand, execCommand, configCommand, opCommand, serverBackupCommand, serverRestoreCommand, whitelistCommand, banCommand, kickCommand, playerOnlineCommand, playerCommand, migrateCommand, modCommand, consoleInitCommand, consoleServiceCommand, consoleUserCommand, consoleApiCommand, consoleRemoveCommand, } from './commands/index.js';
|
|
4
|
+
import { ShellExecutor } from './lib/shell.js';
|
|
5
|
+
const VERSION = '0.1.0';
|
|
6
|
+
/**
|
|
7
|
+
* Handle console command (shared by both 'console' and deprecated 'admin' commands)
|
|
8
|
+
*/
|
|
9
|
+
async function handleConsoleCommand(subCommand, positional, flags, rootDir) {
|
|
10
|
+
switch (subCommand) {
|
|
11
|
+
case 'init':
|
|
12
|
+
return consoleInitCommand({
|
|
13
|
+
root: rootDir,
|
|
14
|
+
force: flags['force'] === true,
|
|
15
|
+
apiPort: flags['api-port'] ? parseInt(flags['api-port'], 10) : undefined,
|
|
16
|
+
consolePort: flags['console-port'] ? parseInt(flags['console-port'], 10) : undefined,
|
|
17
|
+
});
|
|
18
|
+
case 'service':
|
|
19
|
+
return consoleServiceCommand({
|
|
20
|
+
root: rootDir,
|
|
21
|
+
subCommand: positional[0],
|
|
22
|
+
apiOnly: flags['api'] === true,
|
|
23
|
+
consoleOnly: flags['console'] === true,
|
|
24
|
+
follow: flags['follow'] === true,
|
|
25
|
+
json: flags['json'] === true,
|
|
26
|
+
apiPort: flags['api-port'] ? parseInt(flags['api-port'], 10) : undefined,
|
|
27
|
+
consolePort: flags['console-port'] ? parseInt(flags['console-port'], 10) : undefined,
|
|
28
|
+
build: flags['build'] === true,
|
|
29
|
+
noBuild: flags['no-build'] === true,
|
|
30
|
+
});
|
|
31
|
+
case 'user': {
|
|
32
|
+
// Use Commander-based command
|
|
33
|
+
const userCmd = consoleUserCommand();
|
|
34
|
+
userCmd.parse(['node', 'mcctl', ...positional], { from: 'user' });
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
case 'api': {
|
|
38
|
+
// Use Commander-based command
|
|
39
|
+
const apiCmd = consoleApiCommand();
|
|
40
|
+
apiCmd.parse(['node', 'mcctl', ...positional], { from: 'user' });
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
case 'remove':
|
|
44
|
+
return consoleRemoveCommand({
|
|
45
|
+
root: rootDir,
|
|
46
|
+
force: flags['force'] === true,
|
|
47
|
+
keepConfig: flags['keep-config'] === true,
|
|
48
|
+
});
|
|
49
|
+
default:
|
|
50
|
+
log.error('Usage: mcctl console <init|service|user|api|remove>');
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Print usage information
|
|
56
|
+
*/
|
|
57
|
+
function printUsage() {
|
|
58
|
+
console.log(`
|
|
59
|
+
${colors.bold('mcctl')} - Minecraft Server Management CLI
|
|
60
|
+
|
|
61
|
+
${colors.cyan('Usage:')}
|
|
62
|
+
mcctl <command> [options]
|
|
63
|
+
|
|
64
|
+
${colors.cyan('Commands:')}
|
|
65
|
+
${colors.bold('init')} Initialize platform (~/.minecraft-servers)
|
|
66
|
+
${colors.bold('up')} Start all infrastructure (router + servers)
|
|
67
|
+
${colors.bold('down')} Stop all infrastructure
|
|
68
|
+
${colors.bold('router')} <start|stop|restart> Manage mc-router only
|
|
69
|
+
${colors.bold('create')} <name> [options] Create a new server
|
|
70
|
+
${colors.bold('delete')} <name> [--force] Delete a server (preserves world data)
|
|
71
|
+
${colors.bold('status')} [options] Show status of all servers
|
|
72
|
+
${colors.bold('status')} <server> Show detailed status of a server
|
|
73
|
+
${colors.bold('status')} router Show mc-router status with routes
|
|
74
|
+
${colors.bold('start')} <server> [--all] Start a server (--all for all servers)
|
|
75
|
+
${colors.bold('stop')} <server> [--all] Stop a server (--all for all servers)
|
|
76
|
+
${colors.bold('logs')} <server> [lines] View server logs
|
|
77
|
+
${colors.bold('console')} <server> Connect to RCON console
|
|
78
|
+
${colors.bold('exec')} <server> <cmd...> Execute RCON command
|
|
79
|
+
${colors.bold('config')} <server> [key] [val] View/set server config
|
|
80
|
+
|
|
81
|
+
${colors.cyan('Config Shortcuts:')}
|
|
82
|
+
--cheats, --no-cheats Enable/disable cheats (ALLOW_CHEATS)
|
|
83
|
+
--pvp, --no-pvp Enable/disable PvP
|
|
84
|
+
--command-block Enable/disable command blocks
|
|
85
|
+
|
|
86
|
+
${colors.cyan('Player Management:')}
|
|
87
|
+
${colors.bold('op')} <server> <action> [player] Manage operators
|
|
88
|
+
${colors.bold('whitelist')} <server> <action> [player] Manage whitelist
|
|
89
|
+
${colors.bold('ban')} <server> <action> [player/ip] Manage bans
|
|
90
|
+
${colors.bold('kick')} <server> <player> [reason] Kick player
|
|
91
|
+
|
|
92
|
+
${colors.cyan('Operator Actions:')}
|
|
93
|
+
list List current operators
|
|
94
|
+
add <player> Add operator (RCON + config)
|
|
95
|
+
remove <player> Remove operator
|
|
96
|
+
|
|
97
|
+
${colors.cyan('Whitelist Actions:')}
|
|
98
|
+
list Show whitelisted players
|
|
99
|
+
add <player> Add to whitelist
|
|
100
|
+
remove <player> Remove from whitelist
|
|
101
|
+
on / off Enable/disable whitelist
|
|
102
|
+
status Show whitelist status
|
|
103
|
+
|
|
104
|
+
${colors.cyan('Ban Actions:')}
|
|
105
|
+
list Show banned players
|
|
106
|
+
add <player> [reason] Ban player
|
|
107
|
+
remove <player> Unban player
|
|
108
|
+
ip list Show banned IPs
|
|
109
|
+
ip add <ip> [reason] Ban IP
|
|
110
|
+
ip remove <ip> Unban IP
|
|
111
|
+
|
|
112
|
+
${colors.cyan('World Management:')}
|
|
113
|
+
${colors.bold('world list')} [--json] List worlds and lock status
|
|
114
|
+
${colors.bold('world new')} [name] [options] Create new world with seed
|
|
115
|
+
${colors.bold('world assign')} <world> <srv> Lock world to server
|
|
116
|
+
${colors.bold('world release')} <world> Release world lock
|
|
117
|
+
${colors.bold('world delete')} <world> [-f] Delete world permanently
|
|
118
|
+
|
|
119
|
+
${colors.cyan('Mod Management:')}
|
|
120
|
+
${colors.bold('mod search')} <query> Search mods on Modrinth
|
|
121
|
+
${colors.bold('mod add')} <srv> <mod...> Add mods to server
|
|
122
|
+
${colors.bold('mod list')} <server> List configured mods
|
|
123
|
+
${colors.bold('mod remove')} <srv> <mod...> Remove mods from server
|
|
124
|
+
${colors.bold('mod sources')} Show available mod sources
|
|
125
|
+
|
|
126
|
+
${colors.cyan('Mod Add Options:')}
|
|
127
|
+
--modrinth Use Modrinth (default)
|
|
128
|
+
--curseforge Use CurseForge (requires CF_API_KEY)
|
|
129
|
+
--spiget Use Spiget (SpigotMC plugins)
|
|
130
|
+
--url Direct JAR URL download
|
|
131
|
+
|
|
132
|
+
${colors.cyan('Mod Management:')}
|
|
133
|
+
${colors.bold('mod search')} <query> Search mods on Modrinth
|
|
134
|
+
${colors.bold('mod add')} <srv> <mod...> Add mods to server
|
|
135
|
+
${colors.bold('mod list')} <server> List configured mods
|
|
136
|
+
${colors.bold('mod remove')} <srv> <mod...> Remove mods from server
|
|
137
|
+
${colors.bold('mod sources')} Show available mod sources
|
|
138
|
+
|
|
139
|
+
${colors.cyan('Mod Add Options:')}
|
|
140
|
+
--modrinth Use Modrinth (default)
|
|
141
|
+
--curseforge Use CurseForge (requires CF_API_KEY)
|
|
142
|
+
--spiget Use Spiget (SpigotMC plugins)
|
|
143
|
+
--url Direct JAR URL download
|
|
144
|
+
|
|
145
|
+
${colors.cyan('World New Options:')}
|
|
146
|
+
--seed <seed> World seed (optional, random if empty)
|
|
147
|
+
--server <name> Server to assign world to
|
|
148
|
+
--no-start Don't start server after creation
|
|
149
|
+
|
|
150
|
+
${colors.cyan('Player Management (Interactive):')}
|
|
151
|
+
${colors.bold('player')} Interactive mode: server → player → action
|
|
152
|
+
${colors.bold('player')} <server> Interactive mode for specific server
|
|
153
|
+
${colors.bold('player info')} <name> Player info lookup (UUID, skin)
|
|
154
|
+
${colors.bold('player info')} <name> --offline Get offline player info
|
|
155
|
+
${colors.bold('player online')} <server> List online players
|
|
156
|
+
${colors.bold('player online')} --all List online players on all servers
|
|
157
|
+
${colors.bold('player cache')} clear Clear player info cache
|
|
158
|
+
${colors.bold('player cache')} stats Show cache statistics
|
|
159
|
+
|
|
160
|
+
${colors.cyan('Player Lookup (Legacy):')}
|
|
161
|
+
${colors.bold('player lookup')} <name> Look up player info
|
|
162
|
+
${colors.bold('player uuid')} <name> Get player UUID
|
|
163
|
+
|
|
164
|
+
${colors.cyan('Server Backup/Restore:')}
|
|
165
|
+
${colors.bold('server-backup')} <server> [-m msg] Backup server configuration
|
|
166
|
+
${colors.bold('server-backup')} <server> --list List all backups
|
|
167
|
+
${colors.bold('server-restore')} <server> [id] Restore from backup
|
|
168
|
+
|
|
169
|
+
${colors.cyan('World Backup (requires .env config):')}
|
|
170
|
+
${colors.bold('backup push')} [--message] Backup worlds to GitHub
|
|
171
|
+
${colors.bold('backup status')} Show backup configuration
|
|
172
|
+
${colors.bold('backup history')} [--json] Show backup history
|
|
173
|
+
${colors.bold('backup restore')} <commit> Restore from commit
|
|
174
|
+
|
|
175
|
+
${colors.cyan('Migration:')}
|
|
176
|
+
${colors.bold('migrate worlds')} Migrate worlds to shared directory
|
|
177
|
+
${colors.bold('migrate status')} Check migration status
|
|
178
|
+
${colors.bold('migrate worlds')} --all Migrate all servers
|
|
179
|
+
${colors.bold('migrate worlds')} --dry-run Preview changes without applying
|
|
180
|
+
|
|
181
|
+
${colors.cyan('Console Management:')}
|
|
182
|
+
${colors.bold('console init')} [options] Initialize console service (create admin user)
|
|
183
|
+
--force Reinitialize (delete existing config)
|
|
184
|
+
--api-port <port> API server port (default: 3001)
|
|
185
|
+
--console-port <port> Console server port (default: 3000)
|
|
186
|
+
${colors.bold('console user')} <action> [name] Manage console users (list, add, remove, reset)
|
|
187
|
+
${colors.bold('console api')} <action> Manage API settings (status, config, key)
|
|
188
|
+
${colors.bold('console service')} <action> Manage services via PM2 (start, stop, restart, status, logs)
|
|
189
|
+
${colors.bold('console remove')} [options] Remove console service completely
|
|
190
|
+
--force Skip confirmation prompt
|
|
191
|
+
--keep-config Don't delete configuration files
|
|
192
|
+
${colors.dim('admin <cmd> (deprecated, use "console" instead)')}
|
|
193
|
+
|
|
194
|
+
${colors.cyan('Console Options:')}
|
|
195
|
+
--api-port <port> API server port (default: 3001)
|
|
196
|
+
--console-port <port> Console server port (default: 3000)
|
|
197
|
+
--api Target API service only
|
|
198
|
+
--console Target console service only
|
|
199
|
+
-f, --follow Follow log output
|
|
200
|
+
|
|
201
|
+
${colors.cyan('Create Options:')}
|
|
202
|
+
-t, --type TYPE Server type: PAPER, VANILLA, FORGE, FABRIC
|
|
203
|
+
-v, --version VERSION Minecraft version (e.g., 1.21.1)
|
|
204
|
+
-s, --seed NUMBER World seed
|
|
205
|
+
-u, --world-url URL Download world from ZIP URL
|
|
206
|
+
-w, --world NAME Use existing world (symlink)
|
|
207
|
+
--no-start Create without starting
|
|
208
|
+
|
|
209
|
+
${colors.cyan('Status Options:')}
|
|
210
|
+
--detail, -d Show detailed info (memory, CPU, players)
|
|
211
|
+
--watch, -W Real-time monitoring mode
|
|
212
|
+
--interval <sec> Watch refresh interval (default: 5)
|
|
213
|
+
|
|
214
|
+
${colors.cyan('Global Options:')}
|
|
215
|
+
--root <path> Custom data directory
|
|
216
|
+
--sudo-password <pwd> Sudo password for automation (or use MCCTL_SUDO_PASSWORD env)
|
|
217
|
+
--json Output in JSON format
|
|
218
|
+
-h, --help Show this help
|
|
219
|
+
--version Show version
|
|
220
|
+
|
|
221
|
+
${colors.cyan('Examples:')}
|
|
222
|
+
mcctl init
|
|
223
|
+
mcctl up # Start everything
|
|
224
|
+
mcctl down # Stop everything
|
|
225
|
+
mcctl router start # Start mc-router only
|
|
226
|
+
mcctl router restart # Restart mc-router
|
|
227
|
+
mcctl start --all # Start all MC servers
|
|
228
|
+
mcctl stop --all # Stop all MC servers
|
|
229
|
+
mcctl create myserver -t FORGE -v 1.20.4
|
|
230
|
+
mcctl status --json
|
|
231
|
+
mcctl status --detail # Show detailed info
|
|
232
|
+
mcctl status --watch # Real-time monitoring
|
|
233
|
+
mcctl status --watch --interval 2 # Watch with 2s refresh
|
|
234
|
+
mcctl status myserver # Single server status
|
|
235
|
+
mcctl status router # mc-router status
|
|
236
|
+
mcctl logs myserver -f
|
|
237
|
+
mcctl exec myserver say "Hello!" # Execute RCON command
|
|
238
|
+
mcctl exec myserver list # List online players
|
|
239
|
+
mcctl config myserver # View all config
|
|
240
|
+
mcctl config myserver --cheats # Enable cheats
|
|
241
|
+
mcctl config myserver MOTD "Welcome!" # Set MOTD
|
|
242
|
+
mcctl op myserver list # List operators
|
|
243
|
+
mcctl op myserver add Notch # Add operator
|
|
244
|
+
mcctl whitelist myserver add Steve # Add to whitelist
|
|
245
|
+
mcctl ban myserver add Griefer # Ban player
|
|
246
|
+
mcctl kick myserver AFK "Too long" # Kick player
|
|
247
|
+
mcctl player online myserver # Show online players
|
|
248
|
+
mcctl server-backup myserver # Backup server config
|
|
249
|
+
mcctl server-restore myserver # Restore from backup
|
|
250
|
+
`);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Parse command line arguments
|
|
254
|
+
*/
|
|
255
|
+
function parseArgs(args) {
|
|
256
|
+
const result = {
|
|
257
|
+
command: '',
|
|
258
|
+
subCommand: undefined,
|
|
259
|
+
positional: [],
|
|
260
|
+
flags: {},
|
|
261
|
+
};
|
|
262
|
+
let i = 0;
|
|
263
|
+
// Skip node and script path
|
|
264
|
+
while (i < args.length) {
|
|
265
|
+
const arg = args[i];
|
|
266
|
+
if (arg.startsWith('--')) {
|
|
267
|
+
const key = arg.slice(2);
|
|
268
|
+
const nextArg = args[i + 1];
|
|
269
|
+
// Boolean-only flags (never take a value)
|
|
270
|
+
const booleanOnlyFlags = ['all', 'json', 'help', 'version', 'force', 'yes', 'follow', 'detail', 'watch', 'offline', 'no-start', 'list', 'dry-run', 'api', 'console', 'build', 'no-build', 'keep-config'];
|
|
271
|
+
if (booleanOnlyFlags.includes(key)) {
|
|
272
|
+
result.flags[key] = true;
|
|
273
|
+
i++;
|
|
274
|
+
}
|
|
275
|
+
else if (nextArg && !nextArg.startsWith('-')) {
|
|
276
|
+
result.flags[key] = nextArg;
|
|
277
|
+
i += 2;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
result.flags[key] = true;
|
|
281
|
+
i++;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else if (arg.startsWith('-') && arg.length === 2) {
|
|
285
|
+
const key = arg.slice(1);
|
|
286
|
+
const nextArg = args[i + 1];
|
|
287
|
+
// Map short flags to long names
|
|
288
|
+
const flagMap = {
|
|
289
|
+
h: 'help',
|
|
290
|
+
t: 'type',
|
|
291
|
+
v: 'version',
|
|
292
|
+
s: 'seed',
|
|
293
|
+
u: 'world-url',
|
|
294
|
+
w: 'world',
|
|
295
|
+
f: 'follow',
|
|
296
|
+
n: 'lines',
|
|
297
|
+
m: 'message',
|
|
298
|
+
y: 'yes',
|
|
299
|
+
a: 'all',
|
|
300
|
+
d: 'detail',
|
|
301
|
+
W: 'watch',
|
|
302
|
+
};
|
|
303
|
+
const longKey = flagMap[key] ?? key;
|
|
304
|
+
// Boolean-only short flags
|
|
305
|
+
const booleanOnlyShortFlags = ['h', 'f', 'y', 'a', 'd', 'W'];
|
|
306
|
+
if (booleanOnlyShortFlags.includes(key)) {
|
|
307
|
+
result.flags[longKey] = true;
|
|
308
|
+
i++;
|
|
309
|
+
}
|
|
310
|
+
else if (nextArg && !nextArg.startsWith('-')) {
|
|
311
|
+
result.flags[longKey] = nextArg;
|
|
312
|
+
i += 2;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
result.flags[longKey] = true;
|
|
316
|
+
i++;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
if (!result.command) {
|
|
321
|
+
result.command = arg;
|
|
322
|
+
}
|
|
323
|
+
else if (!result.subCommand && ['world', 'player', 'backup', 'op', 'whitelist', 'ban', 'router', 'migrate', 'mod', 'console', 'admin'].includes(result.command)) {
|
|
324
|
+
result.subCommand = arg;
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
result.positional.push(arg);
|
|
328
|
+
}
|
|
329
|
+
i++;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Main entry point
|
|
336
|
+
*/
|
|
337
|
+
async function main() {
|
|
338
|
+
const args = process.argv.slice(2);
|
|
339
|
+
if (args.length === 0) {
|
|
340
|
+
printUsage();
|
|
341
|
+
process.exit(0);
|
|
342
|
+
}
|
|
343
|
+
const parsed = parseArgs(args);
|
|
344
|
+
const { command, subCommand, positional, flags } = parsed;
|
|
345
|
+
// Handle global flags
|
|
346
|
+
if (flags['help'] || command === 'help') {
|
|
347
|
+
printUsage();
|
|
348
|
+
process.exit(0);
|
|
349
|
+
}
|
|
350
|
+
if (flags['version'] || command === '--version') {
|
|
351
|
+
console.log(`mcctl version ${VERSION}`);
|
|
352
|
+
process.exit(0);
|
|
353
|
+
}
|
|
354
|
+
const rootDir = flags['root'];
|
|
355
|
+
const sudoPassword = flags['sudo-password'];
|
|
356
|
+
const paths = new Paths(rootDir);
|
|
357
|
+
const shell = new ShellExecutor({ paths, sudoPassword });
|
|
358
|
+
let exitCode = 0;
|
|
359
|
+
try {
|
|
360
|
+
switch (command) {
|
|
361
|
+
case 'init':
|
|
362
|
+
exitCode = await initCommand({
|
|
363
|
+
root: rootDir,
|
|
364
|
+
skipValidation: flags['skip-validation'] === true,
|
|
365
|
+
skipDocker: flags['skip-docker'] === true,
|
|
366
|
+
});
|
|
367
|
+
break;
|
|
368
|
+
case 'status':
|
|
369
|
+
exitCode = await statusCommand({
|
|
370
|
+
json: flags['json'] === true,
|
|
371
|
+
root: rootDir,
|
|
372
|
+
detail: flags['detail'] === true,
|
|
373
|
+
watch: flags['watch'] === true,
|
|
374
|
+
interval: flags['interval'] ? parseInt(flags['interval'], 10) : undefined,
|
|
375
|
+
serverName: positional[0],
|
|
376
|
+
});
|
|
377
|
+
break;
|
|
378
|
+
case 'up': {
|
|
379
|
+
if (!paths.isInitialized()) {
|
|
380
|
+
log.error('Platform not initialized. Run: mcctl init');
|
|
381
|
+
exitCode = 1;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
exitCode = await shell.up();
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
case 'down': {
|
|
388
|
+
if (!paths.isInitialized()) {
|
|
389
|
+
log.error('Platform not initialized. Run: mcctl init');
|
|
390
|
+
exitCode = 1;
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
exitCode = await shell.down();
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
case 'create': {
|
|
397
|
+
// Use new interactive create command
|
|
398
|
+
// If no name provided, will run in interactive mode
|
|
399
|
+
exitCode = await createCommand({
|
|
400
|
+
root: rootDir,
|
|
401
|
+
name: positional[0],
|
|
402
|
+
type: flags['type'],
|
|
403
|
+
version: flags['version'],
|
|
404
|
+
seed: flags['seed'],
|
|
405
|
+
worldUrl: flags['world-url'],
|
|
406
|
+
worldName: flags['world'],
|
|
407
|
+
noStart: flags['no-start'] === true,
|
|
408
|
+
sudoPassword,
|
|
409
|
+
});
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
case 'delete': {
|
|
413
|
+
// Use new interactive delete command
|
|
414
|
+
// If no name provided, will run in interactive mode with server selection
|
|
415
|
+
exitCode = await deleteCommand({
|
|
416
|
+
root: rootDir,
|
|
417
|
+
name: positional[0],
|
|
418
|
+
force: flags['force'] === true || flags['yes'] === true,
|
|
419
|
+
sudoPassword,
|
|
420
|
+
});
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
case 'start': {
|
|
424
|
+
if (!paths.isInitialized()) {
|
|
425
|
+
log.error('Platform not initialized. Run: mcctl init');
|
|
426
|
+
exitCode = 1;
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
if (flags['all']) {
|
|
430
|
+
exitCode = await shell.startAll();
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
const mcctlArgs = [command, ...positional];
|
|
434
|
+
if (flags['json'])
|
|
435
|
+
mcctlArgs.push('--json');
|
|
436
|
+
exitCode = await shell.mcctl(mcctlArgs);
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
case 'stop': {
|
|
441
|
+
if (!paths.isInitialized()) {
|
|
442
|
+
log.error('Platform not initialized. Run: mcctl init');
|
|
443
|
+
exitCode = 1;
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
if (flags['all']) {
|
|
447
|
+
exitCode = await shell.stopAll();
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
const mcctlArgs = [command, ...positional];
|
|
451
|
+
if (flags['json'])
|
|
452
|
+
mcctlArgs.push('--json');
|
|
453
|
+
exitCode = await shell.mcctl(mcctlArgs);
|
|
454
|
+
}
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
case 'console': {
|
|
458
|
+
// Check if this is console management command (init, service, user, api, remove)
|
|
459
|
+
const consoleManagementSubCommands = ['init', 'service', 'user', 'api', 'remove'];
|
|
460
|
+
if (subCommand && consoleManagementSubCommands.includes(subCommand)) {
|
|
461
|
+
// Route to console management
|
|
462
|
+
exitCode = await handleConsoleCommand(subCommand, positional, flags, rootDir);
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
// Otherwise, treat as RCON console (mcctl console <server>)
|
|
466
|
+
if (!paths.isInitialized()) {
|
|
467
|
+
log.error('Platform not initialized. Run: mcctl init');
|
|
468
|
+
exitCode = 1;
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
// Pass through to mcctl.sh for RCON console
|
|
472
|
+
const mcctlArgs = [command, ...positional];
|
|
473
|
+
if (flags['json'])
|
|
474
|
+
mcctlArgs.push('--json');
|
|
475
|
+
if (flags['follow'])
|
|
476
|
+
mcctlArgs.push('-f');
|
|
477
|
+
if (flags['lines'])
|
|
478
|
+
mcctlArgs.push('-n', flags['lines']);
|
|
479
|
+
exitCode = await shell.mcctl(mcctlArgs);
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
case 'logs': {
|
|
483
|
+
if (!paths.isInitialized()) {
|
|
484
|
+
log.error('Platform not initialized. Run: mcctl init');
|
|
485
|
+
exitCode = 1;
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
// Pass through to mcctl.sh
|
|
489
|
+
const mcctlArgs = [command, ...positional];
|
|
490
|
+
if (flags['json'])
|
|
491
|
+
mcctlArgs.push('--json');
|
|
492
|
+
if (flags['follow'])
|
|
493
|
+
mcctlArgs.push('-f');
|
|
494
|
+
if (flags['lines'])
|
|
495
|
+
mcctlArgs.push('-n', flags['lines']);
|
|
496
|
+
exitCode = await shell.mcctl(mcctlArgs);
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
case 'exec': {
|
|
500
|
+
exitCode = await execCommand({
|
|
501
|
+
root: rootDir,
|
|
502
|
+
serverName: positional[0],
|
|
503
|
+
command: positional.slice(1),
|
|
504
|
+
});
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
case 'config': {
|
|
508
|
+
exitCode = await configCommand({
|
|
509
|
+
root: rootDir,
|
|
510
|
+
serverName: positional[0],
|
|
511
|
+
key: positional[1],
|
|
512
|
+
value: positional[2],
|
|
513
|
+
json: flags['json'] === true,
|
|
514
|
+
cheats: flags['cheats'] === true,
|
|
515
|
+
noCheats: flags['no-cheats'] === true,
|
|
516
|
+
pvp: flags['pvp'] === true,
|
|
517
|
+
noPvp: flags['no-pvp'] === true,
|
|
518
|
+
commandBlock: flags['command-block'] === true,
|
|
519
|
+
noCommandBlock: flags['no-command-block'] === true,
|
|
520
|
+
});
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
case 'world': {
|
|
524
|
+
// Use new interactive world command
|
|
525
|
+
exitCode = await worldCommand({
|
|
526
|
+
root: rootDir,
|
|
527
|
+
subCommand: subCommand,
|
|
528
|
+
worldName: positional[0],
|
|
529
|
+
serverName: subCommand === 'new'
|
|
530
|
+
? flags['server']
|
|
531
|
+
: positional[1],
|
|
532
|
+
seed: flags['seed'],
|
|
533
|
+
autoStart: flags['no-start'] === true ? false : undefined,
|
|
534
|
+
json: flags['json'] === true,
|
|
535
|
+
force: flags['force'] === true,
|
|
536
|
+
});
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
539
|
+
case 'player': {
|
|
540
|
+
// Handle player subcommands
|
|
541
|
+
if (subCommand === 'online') {
|
|
542
|
+
// player online <server> - List online players
|
|
543
|
+
exitCode = await playerOnlineCommand({
|
|
544
|
+
root: rootDir,
|
|
545
|
+
serverName: positional[0],
|
|
546
|
+
all: flags['all'] === true,
|
|
547
|
+
json: flags['json'] === true,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
else if (subCommand === 'info') {
|
|
551
|
+
// player info <name> - Player info lookup
|
|
552
|
+
exitCode = await playerCommand({
|
|
553
|
+
root: rootDir,
|
|
554
|
+
subCommand: 'info',
|
|
555
|
+
playerName: positional[0],
|
|
556
|
+
offline: flags['offline'] === true,
|
|
557
|
+
json: flags['json'] === true,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
else if (subCommand === 'cache') {
|
|
561
|
+
// player cache <clear|stats> - Cache management
|
|
562
|
+
exitCode = await playerCommand({
|
|
563
|
+
root: rootDir,
|
|
564
|
+
subCommand: 'cache',
|
|
565
|
+
cacheAction: positional[0],
|
|
566
|
+
json: flags['json'] === true,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
else if (subCommand === 'lookup' || subCommand === 'uuid') {
|
|
570
|
+
// Legacy lookup commands via shell.player
|
|
571
|
+
const playerArgs = [subCommand, ...positional];
|
|
572
|
+
if (flags['json'])
|
|
573
|
+
playerArgs.push('--json');
|
|
574
|
+
if (flags['offline'])
|
|
575
|
+
playerArgs.push('--offline');
|
|
576
|
+
exitCode = await shell.player(playerArgs);
|
|
577
|
+
}
|
|
578
|
+
else if (!subCommand || subCommand) {
|
|
579
|
+
// Interactive mode: player [server]
|
|
580
|
+
// If subCommand is provided but not a known command, treat it as server name
|
|
581
|
+
exitCode = await playerCommand({
|
|
582
|
+
root: rootDir,
|
|
583
|
+
serverName: subCommand || positional[0],
|
|
584
|
+
json: flags['json'] === true,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
case 'backup': {
|
|
590
|
+
// Use new interactive backup command
|
|
591
|
+
exitCode = await backupCommand({
|
|
592
|
+
root: rootDir,
|
|
593
|
+
subCommand: subCommand,
|
|
594
|
+
message: flags['message'],
|
|
595
|
+
commitHash: positional[0],
|
|
596
|
+
json: flags['json'] === true,
|
|
597
|
+
auto: flags['auto'] === true,
|
|
598
|
+
});
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
case 'op': {
|
|
602
|
+
// op command: op <server> <action> [player]
|
|
603
|
+
// parseArgs treats second arg as subCommand, so:
|
|
604
|
+
// subCommand = server name, positional[0] = action, positional[1] = player
|
|
605
|
+
exitCode = await opCommand({
|
|
606
|
+
root: rootDir,
|
|
607
|
+
serverName: subCommand,
|
|
608
|
+
subCommand: positional[0],
|
|
609
|
+
playerName: positional[1],
|
|
610
|
+
json: flags['json'] === true,
|
|
611
|
+
});
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
case 'server-backup': {
|
|
615
|
+
exitCode = await serverBackupCommand({
|
|
616
|
+
root: rootDir,
|
|
617
|
+
serverName: positional[0],
|
|
618
|
+
message: flags['message'],
|
|
619
|
+
list: flags['list'] === true,
|
|
620
|
+
json: flags['json'] === true,
|
|
621
|
+
});
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
case 'server-restore': {
|
|
625
|
+
exitCode = await serverRestoreCommand({
|
|
626
|
+
root: rootDir,
|
|
627
|
+
serverName: positional[0],
|
|
628
|
+
backupId: positional[1],
|
|
629
|
+
force: flags['force'] === true,
|
|
630
|
+
dryRun: flags['dry-run'] === true,
|
|
631
|
+
json: flags['json'] === true,
|
|
632
|
+
});
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
case 'whitelist': {
|
|
636
|
+
// whitelist command: whitelist <server> <action> [player]
|
|
637
|
+
// subCommand = server name, positional[0] = action, positional[1] = player
|
|
638
|
+
exitCode = await whitelistCommand({
|
|
639
|
+
root: rootDir,
|
|
640
|
+
serverName: subCommand,
|
|
641
|
+
subCommand: positional[0],
|
|
642
|
+
playerName: positional[1],
|
|
643
|
+
json: flags['json'] === true,
|
|
644
|
+
});
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
case 'ban': {
|
|
648
|
+
// ban command: ban <server> <action> [target] [reason...]
|
|
649
|
+
// subCommand = server name, positional[0] = action, positional[1] = target
|
|
650
|
+
const action = positional[0];
|
|
651
|
+
let ipAction;
|
|
652
|
+
let target;
|
|
653
|
+
let reason;
|
|
654
|
+
if (action === 'ip') {
|
|
655
|
+
// ban <server> ip <list|add|remove> [ip] [reason]
|
|
656
|
+
ipAction = positional[1];
|
|
657
|
+
target = positional[2];
|
|
658
|
+
reason = positional.slice(3).join(' ') || undefined;
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
target = positional[1];
|
|
662
|
+
reason = positional.slice(2).join(' ') || undefined;
|
|
663
|
+
}
|
|
664
|
+
exitCode = await banCommand({
|
|
665
|
+
root: rootDir,
|
|
666
|
+
serverName: subCommand,
|
|
667
|
+
subCommand: action,
|
|
668
|
+
target,
|
|
669
|
+
reason,
|
|
670
|
+
ipAction,
|
|
671
|
+
json: flags['json'] === true,
|
|
672
|
+
});
|
|
673
|
+
break;
|
|
674
|
+
}
|
|
675
|
+
case 'kick': {
|
|
676
|
+
// kick command: kick <server> <player> [reason...]
|
|
677
|
+
const serverName = positional[0];
|
|
678
|
+
const playerName = positional[1];
|
|
679
|
+
const reason = positional.slice(2).join(' ') || undefined;
|
|
680
|
+
exitCode = await kickCommand({
|
|
681
|
+
root: rootDir,
|
|
682
|
+
serverName,
|
|
683
|
+
playerName,
|
|
684
|
+
reason,
|
|
685
|
+
json: flags['json'] === true,
|
|
686
|
+
});
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
case 'router': {
|
|
690
|
+
if (!paths.isInitialized()) {
|
|
691
|
+
log.error('Platform not initialized. Run: mcctl init');
|
|
692
|
+
exitCode = 1;
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
switch (subCommand) {
|
|
696
|
+
case 'start':
|
|
697
|
+
exitCode = await shell.routerStart();
|
|
698
|
+
break;
|
|
699
|
+
case 'stop':
|
|
700
|
+
exitCode = await shell.routerStop();
|
|
701
|
+
break;
|
|
702
|
+
case 'restart':
|
|
703
|
+
exitCode = await shell.routerRestart();
|
|
704
|
+
break;
|
|
705
|
+
default:
|
|
706
|
+
log.error('Usage: mcctl router <start|stop|restart>');
|
|
707
|
+
exitCode = 1;
|
|
708
|
+
}
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
case 'migrate': {
|
|
712
|
+
// migrate command: migrate [worlds|status] [options]
|
|
713
|
+
exitCode = await migrateCommand({
|
|
714
|
+
root: rootDir,
|
|
715
|
+
subCommand: subCommand,
|
|
716
|
+
serverName: flags['server'],
|
|
717
|
+
all: flags['all'] === true,
|
|
718
|
+
dryRun: flags['dry-run'] === true,
|
|
719
|
+
backup: flags['backup'] === true,
|
|
720
|
+
force: flags['force'] === true,
|
|
721
|
+
json: flags['json'] === true,
|
|
722
|
+
});
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
case 'mod': {
|
|
726
|
+
// mod command: mod [search|add|list|remove|sources] [args...]
|
|
727
|
+
// subCommand = action, positional[0] = server or query, positional[1+] = mod names
|
|
728
|
+
const modSource = flags['modrinth'] ? 'modrinth' :
|
|
729
|
+
flags['curseforge'] ? 'curseforge' :
|
|
730
|
+
flags['spiget'] ? 'spiget' :
|
|
731
|
+
flags['url'] ? 'url' : 'modrinth';
|
|
732
|
+
exitCode = await modCommand({
|
|
733
|
+
root: rootDir,
|
|
734
|
+
subCommand: subCommand,
|
|
735
|
+
serverName: subCommand === 'search' ? undefined : positional[0],
|
|
736
|
+
query: subCommand === 'search' ? positional[0] : undefined,
|
|
737
|
+
modNames: subCommand === 'search' ? undefined : positional.slice(1),
|
|
738
|
+
source: modSource,
|
|
739
|
+
json: flags['json'] === true,
|
|
740
|
+
force: flags['force'] === true,
|
|
741
|
+
});
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
744
|
+
case 'admin': {
|
|
745
|
+
// Show deprecation warning for 'admin' command
|
|
746
|
+
log.warn('The "admin" command is deprecated. Please use "console" instead.');
|
|
747
|
+
console.log(` Example: ${colors.cyan('mcctl console init')} instead of ${colors.dim('mcctl admin init')}`);
|
|
748
|
+
console.log('');
|
|
749
|
+
// Route to console management handler
|
|
750
|
+
exitCode = await handleConsoleCommand(subCommand, positional, flags, rootDir);
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
default:
|
|
754
|
+
log.error(`Unknown command: ${command}`);
|
|
755
|
+
printUsage();
|
|
756
|
+
exitCode = 1;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
catch (err) {
|
|
760
|
+
log.error(`Unexpected error: ${err instanceof Error ? err.message : String(err)}`);
|
|
761
|
+
exitCode = 1;
|
|
762
|
+
}
|
|
763
|
+
process.exit(exitCode);
|
|
764
|
+
}
|
|
765
|
+
main();
|
|
766
|
+
//# sourceMappingURL=index.js.map
|