@powernukkitx/cli 1.0.0 → 1.0.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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -203
  3. package/dist/cli.js +34 -46
  4. package/dist/commands/backup.d.ts +2 -2
  5. package/dist/commands/backup.js +23 -24
  6. package/dist/commands/config.d.ts +1 -1
  7. package/dist/commands/config.js +60 -61
  8. package/dist/commands/console.d.ts +2 -2
  9. package/dist/commands/console.js +98 -99
  10. package/dist/commands/doctor.d.ts +2 -2
  11. package/dist/commands/doctor.js +97 -98
  12. package/dist/commands/info.d.ts +2 -2
  13. package/dist/commands/info.js +41 -42
  14. package/dist/commands/init.d.ts +2 -2
  15. package/dist/commands/init.js +87 -66
  16. package/dist/commands/install.js +45 -0
  17. package/dist/commands/logs.d.ts +2 -2
  18. package/dist/commands/logs.js +60 -61
  19. package/dist/commands/menu.js +94 -86
  20. package/dist/commands/plugin/index.d.ts +2 -2
  21. package/dist/commands/plugin/index.js +13 -13
  22. package/dist/commands/plugin/info.d.ts +2 -2
  23. package/dist/commands/plugin/info.js +39 -40
  24. package/dist/commands/plugin/install.d.ts +2 -2
  25. package/dist/commands/plugin/install.js +56 -57
  26. package/dist/commands/plugin/installed.d.ts +2 -2
  27. package/dist/commands/plugin/installed.js +41 -42
  28. package/dist/commands/plugin/list.d.ts +2 -2
  29. package/dist/commands/plugin/list.js +47 -49
  30. package/dist/commands/plugin/remove.d.ts +2 -2
  31. package/dist/commands/plugin/remove.js +44 -45
  32. package/dist/commands/plugin/search.d.ts +2 -2
  33. package/dist/commands/plugin/search.js +11 -12
  34. package/dist/commands/plugin/update.d.ts +2 -2
  35. package/dist/commands/plugin/update.js +52 -53
  36. package/dist/commands/start.d.ts +2 -2
  37. package/dist/commands/start.js +74 -75
  38. package/dist/commands/stop.d.ts +2 -2
  39. package/dist/commands/stop.js +26 -27
  40. package/dist/commands/update.d.ts +2 -2
  41. package/dist/commands/update.js +34 -35
  42. package/dist/commands/use.d.ts +2 -2
  43. package/dist/commands/use.js +39 -40
  44. package/dist/infra/http.js +119 -121
  45. package/dist/infra/paths.js +15 -20
  46. package/dist/infra/store.js +24 -27
  47. package/dist/services/backup.js +34 -40
  48. package/dist/services/plugins.js +139 -111
  49. package/dist/services/process.js +41 -43
  50. package/dist/services/release.js +51 -38
  51. package/dist/services/server.js +81 -89
  52. package/dist/ui/output.js +67 -71
  53. package/dist/ui/prompts.js +26 -30
  54. package/dist/ui/theme.js +16 -18
  55. package/package.json +44 -46
  56. package/dist/bundle.js +0 -18
  57. package/dist/commands/cfg.d.ts +0 -2
  58. package/dist/commands/cfg.js +0 -61
  59. package/dist/commands/lang.d.ts +0 -2
  60. package/dist/commands/lang.js +0 -28
  61. package/dist/commands/plugin.d.ts +0 -1
  62. package/dist/commands/plugin.js +0 -1
  63. package/dist/core/config.d.ts +0 -13
  64. package/dist/core/config.js +0 -31
  65. package/dist/core/network.d.ts +0 -13
  66. package/dist/core/network.js +0 -139
  67. package/dist/core/output.d.ts +0 -33
  68. package/dist/core/output.js +0 -75
  69. package/dist/core/process.d.ts +0 -10
  70. package/dist/core/process.js +0 -53
  71. package/dist/i18n/en.json +0 -174
  72. package/dist/i18n/fr.json +0 -174
  73. package/dist/i18n/index.js +0 -58
  74. package/dist/index.d.ts +0 -1
  75. package/dist/index.js +0 -1
  76. package/dist/lang/en.json +0 -146
  77. package/dist/lang/fr.json +0 -146
  78. package/dist/lang/index.d.ts +0 -7
  79. package/dist/lang/index.js +0 -83
  80. package/dist/main.d.ts +0 -2
  81. package/dist/main.js +0 -28
  82. package/dist/plugins.json +0 -66
  83. package/dist/types.d.ts +0 -61
  84. package/dist/types.js +0 -1
  85. package/dist/utils/api.d.ts +0 -9
  86. package/dist/utils/api.js +0 -24
  87. package/dist/utils/github.d.ts +0 -20
  88. package/dist/utils/github.js +0 -60
  89. package/dist/utils/logger.d.ts +0 -15
  90. package/dist/utils/logger.js +0 -72
  91. package/dist/utils/pause.d.ts +0 -1
  92. package/dist/utils/pause.js +0 -6
  93. package/dist/utils/plugins.d.ts +0 -4
  94. package/dist/utils/plugins.js +0 -34
  95. package/dist/utils/server.d.ts +0 -3
  96. package/dist/utils/server.js +0 -32
  97. package/dist/utils/updater.d.ts +0 -1
  98. package/dist/utils/updater.js +0 -86
@@ -1,42 +1,41 @@
1
- import { existsSync } from 'node:fs';
2
- import { readdir } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { freemem, totalmem } from 'node:os';
5
- import { defineCommand } from 'citty';
6
- import { intro, outro, log, section, isJson, json } from '../ui/output.js';
7
- import { c } from '../ui/theme.js';
8
- import { resolveServerDir } from '../services/server.js';
9
- import { t } from '../i18n/index.js';
10
- export const infoCmd = defineCommand({
11
- meta: { description: 'Show server information' },
12
- args: {},
13
- async run() {
14
- const serverPath = await resolveServerDir();
15
- const installed = serverPath !== null;
16
- let plugins = [], worlds = [];
17
- if (serverPath && existsSync(join(serverPath, 'plugins'))) {
18
- plugins = (await readdir(join(serverPath, 'plugins'))).filter(f => f.endsWith('.jar'));
19
- }
20
- if (serverPath && existsSync(join(serverPath, 'worlds'))) {
21
- worlds = await readdir(join(serverPath, 'worlds'));
22
- }
23
- const freeMb = Math.round(freemem() / 1024 / 1024);
24
- const totalMb = Math.round(totalmem() / 1024 / 1024);
25
- if (isJson())
26
- json({
27
- status: installed ? 'installed' : 'not_installed',
28
- serverDir: serverPath, plugins: plugins.length, worlds: worlds.length,
29
- ram: { freeMb, totalMb },
30
- });
31
- intro(`📊 ${t('info.title')}`);
32
- section(t('info.server'));
33
- log.info(`${t('info.status').padEnd(12)} ${installed ? c.green('✔ ' + t('info.installed')) : c.red('✘ ' + t('info.notInstalled'))}`);
34
- if (serverPath)
35
- log.info(`${t('info.path').padEnd(12)} ${c.accent(serverPath)}`);
36
- log.info(`${t('info.plugins').padEnd(12)} ${plugins.length}`);
37
- log.info(`${t('info.worlds').padEnd(12)} ${worlds.length}`);
38
- section(t('info.system'));
39
- log.info(`${t('info.ram').padEnd(12)} ${freeMb} Mo / ${totalMb} Mo`);
40
- outro(installed ? t('info.ready') : t('info.notReady'));
41
- },
42
- });
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { freemem, totalmem } from 'node:os';
5
+ import { defineCommand } from 'citty';
6
+ import { intro, outro, log, section, isJson, json } from '../ui/output.js';
7
+ import { c } from '../ui/theme.js';
8
+ import { resolveServerDir } from '../services/server.js';
9
+ export const infoCmd = defineCommand({
10
+ meta: { description: 'Show server information' },
11
+ args: {},
12
+ async run() {
13
+ const serverPath = await resolveServerDir();
14
+ const installed = serverPath !== null;
15
+ let plugins = [], worlds = [];
16
+ if (serverPath && existsSync(join(serverPath, 'plugins'))) {
17
+ plugins = (await readdir(join(serverPath, 'plugins'))).filter(f => f.endsWith('.jar'));
18
+ }
19
+ if (serverPath && existsSync(join(serverPath, 'worlds'))) {
20
+ worlds = await readdir(join(serverPath, 'worlds'));
21
+ }
22
+ const freeMb = Math.round(freemem() / 1024 / 1024);
23
+ const totalMb = Math.round(totalmem() / 1024 / 1024);
24
+ if (isJson())
25
+ json({
26
+ status: installed ? 'installed' : 'not_installed',
27
+ serverDir: serverPath, plugins: plugins.length, worlds: worlds.length,
28
+ ram: { freeMb, totalMb },
29
+ });
30
+ intro(`📊 ${"Server info"}`);
31
+ section("Server");
32
+ log.info(`${"Status".padEnd(12)} ${installed ? c.green('✔ ' + "Installed") : c.red('✘ ' + "Not installed")}`);
33
+ if (serverPath)
34
+ log.info(`${"Path".padEnd(12)} ${c.accent(serverPath)}`);
35
+ log.info(`${"Plugins".padEnd(12)} ${plugins.length}`);
36
+ log.info(`${"Worlds".padEnd(12)} ${worlds.length}`);
37
+ section("System");
38
+ log.info(`${"Free RAM".padEnd(12)} ${freeMb} MB / ${totalMb} MB`);
39
+ outro(installed ? "Ready to start with 'pnx start'" : "Run 'pnx init' to create a server");
40
+ },
41
+ });
@@ -1,2 +1,2 @@
1
- import type { CommandDef } from 'citty';
2
- export declare const initCmd: CommandDef;
1
+ import type { CommandDef } from 'citty';
2
+ export declare const initCmd: CommandDef;
@@ -1,66 +1,87 @@
1
- import { existsSync } from 'node:fs';
2
- import { mkdir } from 'node:fs/promises';
3
- import { join, resolve } from 'node:path';
4
- import { cwd } from 'node:process';
5
- import { defineCommand } from 'citty';
6
- import { intro, outro, log, spin, progress } from '../ui/output.js';
7
- import { promptText, promptConfirm } from '../ui/prompts.js';
8
- import { getLatestRelease, downloadCore } from '../services/release.js';
9
- import { startScripts } from '../services/server.js';
10
- import { downloadFile } from '../infra/http.js';
11
- import { JAR_NAME } from '../infra/paths.js';
12
- import { t } from '../i18n/index.js';
13
- export const initCmd = defineCommand({
14
- meta: { description: 'Create a new PowerNukkitX server' },
15
- args: {
16
- dir: { type: 'string', description: 'Target directory' },
17
- dev: { type: 'boolean', description: 'Install dev version', default: false },
18
- },
19
- async run({ args }) {
20
- intro(`⚡ ${t('init.title')}`);
21
- let target = args.dir;
22
- if (!target) {
23
- target = await promptText({
24
- message: t('init.promptDir'),
25
- defaultValue: 'pnx-server',
26
- validate: v => {
27
- if (!v || !v.trim())
28
- return 'Required';
29
- if (existsSync(join(resolve(cwd(), v), JAR_NAME)))
30
- return t('init.alreadyExists');
31
- return undefined;
32
- },
33
- });
34
- }
35
- const serverDir = resolve(cwd(), target);
36
- if (existsSync(join(serverDir, JAR_NAME)) && args.dir) {
37
- log.error(t('init.alreadyExists'));
38
- process.exit(1);
39
- }
40
- try {
41
- const sp = spin(t('init.fetchingInfo'));
42
- const release = await getLatestRelease();
43
- sp.stop(`${t('init.latestVersion')}: ${release.tag}`);
44
- await mkdir(serverDir, { recursive: true });
45
- log.step(t('init.downloading'));
46
- const { size } = await downloadCore(release, join(serverDir, JAR_NAME), pct => progress(pct, JAR_NAME));
47
- log.success(t('init.downloaded', (size / 1024 / 1024).toFixed(1)));
48
- const sp2 = spin(t('init.downloadingScripts'));
49
- for (const s of startScripts())
50
- await downloadFile(s.url, join(serverDir, s.name));
51
- sp2.stop(t('init.scriptsDownloaded'));
52
- log.success(t('init.success'));
53
- if (await promptConfirm(t('init.launchPrompt'), false)) {
54
- const { runStart } = await import('./start.js');
55
- await runStart({ dir: serverDir });
56
- }
57
- else {
58
- outro(t('init.success'));
59
- }
60
- }
61
- catch (e) {
62
- log.error(e.message);
63
- process.exit(1);
64
- }
65
- },
66
- });
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir } from 'node:fs/promises';
3
+ import { join, resolve } from 'node:path';
4
+ import { cwd } from 'node:process';
5
+ import { defineCommand } from 'citty';
6
+ import { intro, outro, log, spin, progress, isJson } from '../ui/output.js';
7
+ import { promptText, promptConfirm, promptSelect } from '../ui/prompts.js';
8
+ import { listReleases, downloadCore } from '../services/release.js';
9
+ import { startScripts, setDefaultServer } from '../services/server.js';
10
+ import { downloadFile } from '../infra/http.js';
11
+ import { JAR_NAME } from '../infra/paths.js';
12
+ export const initCmd = defineCommand({
13
+ meta: { description: 'Create a new PowerNukkitX server' },
14
+ args: {
15
+ dir: { type: 'string', description: 'Target directory' },
16
+ version: { type: 'string', description: 'Version to install (tag), skips the picker' },
17
+ dev: { type: 'boolean', description: 'Install dev version', default: false },
18
+ },
19
+ async run({ args }) {
20
+ intro(`⚡ ${"Create a PowerNukkitX server"}`);
21
+ let target = args.dir;
22
+ if (!target) {
23
+ target = await promptText({
24
+ message: "Server directory?",
25
+ defaultValue: 'pnx-server',
26
+ validate: v => {
27
+ if (!v || !v.trim())
28
+ return 'Required';
29
+ if (existsSync(join(resolve(cwd(), v), JAR_NAME)))
30
+ return "A server already exists here";
31
+ return undefined;
32
+ },
33
+ });
34
+ }
35
+ const serverDir = resolve(cwd(), target);
36
+ if (existsSync(join(serverDir, JAR_NAME)) && args.dir) {
37
+ log.error("A server already exists here");
38
+ process.exit(1);
39
+ }
40
+ try {
41
+ const sp = spin("Fetching versions...");
42
+ const releases = await listReleases();
43
+ sp.stop(`${String(releases.length)} versions found`);
44
+ if (releases.length === 0)
45
+ throw new Error("No releases available");
46
+ let release;
47
+ if (args.version) {
48
+ const wanted = args.version.replace(/^v/, '');
49
+ release = releases.find(r => r.tag === args.version || r.version === wanted);
50
+ if (!release)
51
+ throw new Error(`Version ${args.version} not found`);
52
+ }
53
+ else if (isJson()) {
54
+ release = releases[0];
55
+ }
56
+ else {
57
+ const chosen = await promptSelect("Select a version", releases.map((r, i) => ({
58
+ value: r.tag,
59
+ label: i === 0 ? `${r.tag} (${"latest"})` : r.tag,
60
+ hint: r.prerelease ? "pre-release" : undefined,
61
+ })));
62
+ release = releases.find(r => r.tag === chosen) ?? releases[0];
63
+ }
64
+ await mkdir(serverDir, { recursive: true });
65
+ log.step("Downloading");
66
+ const { size } = await downloadCore(release, join(serverDir, JAR_NAME), pct => progress(pct, JAR_NAME));
67
+ log.success(`Downloaded (${(size / 1024 / 1024).toFixed(1)} MB)`);
68
+ const sp2 = spin("Downloading start scripts...");
69
+ for (const s of startScripts())
70
+ await downloadFile(s.url, join(serverDir, s.name));
71
+ sp2.stop("Start scripts downloaded");
72
+ await setDefaultServer(serverDir);
73
+ log.success("Server ready!");
74
+ if (await promptConfirm("Start the server now?", false)) {
75
+ const { runStart } = await import('./start.js');
76
+ await runStart({ dir: serverDir });
77
+ }
78
+ else {
79
+ outro("Server ready!");
80
+ }
81
+ }
82
+ catch (e) {
83
+ log.error(e.message);
84
+ process.exit(1);
85
+ }
86
+ },
87
+ });
@@ -0,0 +1,45 @@
1
+ import { join } from 'node:path';
2
+ import { defineCommand } from 'citty';
3
+ import { intro, outro, log, spin, progress } from '../ui/output.js';
4
+ import { promptText } from '../ui/prompts.js';
5
+ import { resolveServerDir } from '../services/server.js';
6
+ import { installApprovedPlugin } from '../services/plugins.js';
7
+ export async function runInstall(slug) {
8
+ intro(`📦 ${"Install plugin"}`);
9
+ let name = slug?.trim();
10
+ if (!name) {
11
+ const answer = await promptText({ message: "Plugin slug? (owner.name)", placeholder: 'Owner.Plugin' });
12
+ name = answer?.trim();
13
+ }
14
+ if (!name) {
15
+ log.info("No plugin specified");
16
+ outro('');
17
+ return;
18
+ }
19
+ const serverPath = (await resolveServerDir()) ?? '.';
20
+ const pluginsDir = join(serverPath, 'plugins');
21
+ const sp = spin(name);
22
+ try {
23
+ const entry = await installApprovedPlugin(name, pluginsDir, (pct, f) => progress(pct, f));
24
+ sp.stop(`${entry.name} v${entry.version}`);
25
+ log.success(`Installed ${entry.name}`);
26
+ log.info("Restart the server to load plugins");
27
+ }
28
+ catch (e) {
29
+ const msg = e?.message ?? '';
30
+ if (msg.startsWith('not-approved'))
31
+ sp.fail(`${name} is not approved or does not exist`);
32
+ else if (msg.startsWith('no-file'))
33
+ sp.fail(`No file for ${name}`);
34
+ else
35
+ sp.fail(`Failed to install ${name}`);
36
+ }
37
+ outro('');
38
+ }
39
+ export const installCmd = defineCommand({
40
+ meta: { name: 'install', description: 'Install an approved plugin by slug (owner.name)' },
41
+ args: { slug: { type: 'positional', description: 'Plugin slug, e.g. RedstoneCloud.CloudBridge', required: false } },
42
+ async run({ args }) {
43
+ await runInstall(args.slug);
44
+ },
45
+ });
@@ -1,2 +1,2 @@
1
- import type { CommandDef } from 'citty';
2
- export declare const logsCmd: CommandDef;
1
+ import type { CommandDef } from 'citty';
2
+ export declare const logsCmd: CommandDef;
@@ -1,61 +1,60 @@
1
- import { existsSync, readdirSync, statSync, readFileSync, watch } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { defineCommand } from 'citty';
4
- import { intro, log } from '../ui/output.js';
5
- import { c } from '../ui/theme.js';
6
- import { resolveServerDir } from '../services/server.js';
7
- import { t } from '../i18n/index.js';
8
- export const logsCmd = defineCommand({
9
- meta: { description: 'View server logs' },
10
- args: {
11
- lines: { type: 'string', description: 'Number of lines to show', default: '50' },
12
- follow: { type: 'boolean', description: 'Follow log output', default: true },
13
- },
14
- async run({ args }) {
15
- intro(`📋 ${t('logs.title')}`);
16
- const serverPath = await resolveServerDir();
17
- if (!serverPath) {
18
- log.error(t('logs.noServer'));
19
- process.exit(1);
20
- }
21
- const logsDir = join(serverPath, 'logs');
22
- if (!existsSync(logsDir)) {
23
- log.error(t('logs.noLogs'));
24
- process.exit(1);
25
- }
26
- const files = readdirSync(logsDir)
27
- .filter(f => f.endsWith('.log') || f === 'latest.log')
28
- .map(f => ({ name: f, mtime: statSync(join(logsDir, f)).mtime.getTime() }))
29
- .sort((a, b) => b.mtime - a.mtime);
30
- if (files.length === 0) {
31
- log.error(t('logs.noLogs'));
32
- process.exit(1);
33
- }
34
- const logPath = join(logsDir, files[0].name);
35
- log.step(t('logs.watching', files[0].name));
36
- const n = parseInt(args.lines) || 50;
37
- const content = readFileSync(logPath, 'utf-8');
38
- const colorize = (line) => line.replace(/\[ERROR\]/g, c.red('[ERROR]'))
39
- .replace(/\[WARN\]/g, c.yellow('[WARN]'))
40
- .replace(/\[INFO\]/g, c.blue('[INFO]'));
41
- for (const line of content.split('\n').filter(Boolean).slice(-n)) {
42
- process.stdout.write(colorize(line) + '\n');
43
- }
44
- if (args.follow) {
45
- log.dim(t('logs.liveMode'));
46
- process.on('SIGINT', () => { process.stdout.write('\n'); process.exit(0); });
47
- let buf = content;
48
- watch(logPath, () => {
49
- try {
50
- const updated = readFileSync(logPath, 'utf-8');
51
- if (updated.length > buf.length) {
52
- process.stdout.write(updated.slice(buf.length));
53
- buf = updated;
54
- }
55
- }
56
- catch { /* rotation en cours */ }
57
- });
58
- await new Promise(() => { });
59
- }
60
- },
61
- });
1
+ import { existsSync, readdirSync, statSync, readFileSync, watch } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { defineCommand } from 'citty';
4
+ import { intro, log } from '../ui/output.js';
5
+ import { c } from '../ui/theme.js';
6
+ import { resolveServerDir } from '../services/server.js';
7
+ export const logsCmd = defineCommand({
8
+ meta: { description: 'View server logs' },
9
+ args: {
10
+ lines: { type: 'string', description: 'Number of lines to show', default: '50' },
11
+ follow: { type: 'boolean', description: 'Follow log output', default: true },
12
+ },
13
+ async run({ args }) {
14
+ intro(`📋 ${"Server logs"}`);
15
+ const serverPath = await resolveServerDir();
16
+ if (!serverPath) {
17
+ log.error("No server detected");
18
+ process.exit(1);
19
+ }
20
+ const logsDir = join(serverPath, 'logs');
21
+ if (!existsSync(logsDir)) {
22
+ log.error("No log files found");
23
+ process.exit(1);
24
+ }
25
+ const files = readdirSync(logsDir)
26
+ .filter(f => f.endsWith('.log') || f === 'latest.log')
27
+ .map(f => ({ name: f, mtime: statSync(join(logsDir, f)).mtime.getTime() }))
28
+ .sort((a, b) => b.mtime - a.mtime);
29
+ if (files.length === 0) {
30
+ log.error("No log files found");
31
+ process.exit(1);
32
+ }
33
+ const logPath = join(logsDir, files[0].name);
34
+ log.step(`Reading ${files[0].name}`);
35
+ const n = parseInt(args.lines) || 50;
36
+ const content = readFileSync(logPath, 'utf-8');
37
+ const colorize = (line) => line.replace(/\[ERROR\]/g, c.red('[ERROR]'))
38
+ .replace(/\[WARN\]/g, c.yellow('[WARN]'))
39
+ .replace(/\[INFO\]/g, c.blue('[INFO]'));
40
+ for (const line of content.split('\n').filter(Boolean).slice(-n)) {
41
+ process.stdout.write(colorize(line) + '\n');
42
+ }
43
+ if (args.follow) {
44
+ log.dim("Live mode (Ctrl+C to quit)");
45
+ process.on('SIGINT', () => { process.stdout.write('\n'); process.exit(0); });
46
+ let buf = content;
47
+ watch(logPath, () => {
48
+ try {
49
+ const updated = readFileSync(logPath, 'utf-8');
50
+ if (updated.length > buf.length) {
51
+ process.stdout.write(updated.slice(buf.length));
52
+ buf = updated;
53
+ }
54
+ }
55
+ catch { }
56
+ });
57
+ await new Promise(() => { });
58
+ }
59
+ },
60
+ });
@@ -1,86 +1,94 @@
1
- import { intro, outro, log } from '../ui/output.js';
2
- import { promptSelect } from '../ui/prompts.js';
3
- import { detectServers } from '../services/server.js';
4
- import { loadPid, isAlive } from '../services/process.js';
5
- import { t } from '../i18n/index.js';
6
- /** Menu interactif racine, contextuel à l'état du serveur. */
7
- export async function runMenu() {
8
- const servers = detectServers();
9
- const hasServer = servers.length > 0;
10
- const pid = await loadPid();
11
- const running = pid !== null && isAlive(pid.pid);
12
- intro(`⚡ ${t('menu.title')}`);
13
- if (running)
14
- log.info(t('menu.statusRunning', String(pid.pid)));
15
- else if (hasServer)
16
- log.info(t('menu.statusStopped'));
17
- else
18
- log.warn(t('menu.statusNoServer'));
19
- const options = [];
20
- if (!hasServer)
21
- options.push({ value: 'create', label: t('menu.create') });
22
- if (hasServer && !running)
23
- options.push({ value: 'start', label: t('menu.start') });
24
- if (running)
25
- options.push({ value: 'stop', label: t('menu.stop') });
26
- if (hasServer) {
27
- options.push({ value: 'plugins', label: t('menu.plugins') });
28
- options.push({ value: 'update', label: t('menu.update') });
29
- options.push({ value: 'backup', label: t('menu.backup') });
30
- }
31
- options.push({ value: 'doctor', label: t('menu.doctor') });
32
- options.push({ value: 'info', label: t('menu.info') });
33
- options.push({ value: 'lang', label: t('menu.lang') });
34
- options.push({ value: 'quit', label: t('menu.quit') });
35
- const choice = await promptSelect(t('menu.prompt'), options);
36
- switch (choice) {
37
- case 'create': {
38
- const { initCmd } = await import('./init.js');
39
- await initCmd.run({ args: {} });
40
- break;
41
- }
42
- case 'start': {
43
- const { runStart } = await import('./start.js');
44
- await runStart({});
45
- break;
46
- }
47
- case 'stop': {
48
- const { runStop } = await import('./stop.js');
49
- await runStop();
50
- break;
51
- }
52
- case 'plugins': {
53
- const { installCmd } = await import('./plugin/install.js');
54
- await installCmd.run({ args: {} });
55
- break;
56
- }
57
- case 'update': {
58
- const { runUpdate } = await import('./update.js');
59
- await runUpdate();
60
- break;
61
- }
62
- case 'backup': {
63
- const { runBackup } = await import('./backup.js');
64
- await runBackup();
65
- break;
66
- }
67
- case 'doctor': {
68
- const { doctorCmd } = await import('./doctor.js');
69
- await doctorCmd.run({ args: {} });
70
- break;
71
- }
72
- case 'info': {
73
- const { infoCmd } = await import('./info.js');
74
- await infoCmd.run({ args: {} });
75
- break;
76
- }
77
- case 'lang': {
78
- const { langCmd } = await import('./lang.js');
79
- await langCmd.run({ args: {} });
80
- break;
81
- }
82
- case 'quit':
83
- outro(t('menu.bye'));
84
- break;
85
- }
86
- }
1
+ import { intro, outro, log } from '../ui/output.js';
2
+ import { promptSelect, promptText } from '../ui/prompts.js';
3
+ import { resolveServerDir } from '../services/server.js';
4
+ import { loadPid, isAlive } from '../services/process.js';
5
+ import { c } from '../ui/theme.js';
6
+ export async function runMenu() {
7
+ while (true) {
8
+ const done = await menuStep();
9
+ if (done)
10
+ return;
11
+ await promptText({ message: "Press enter to return to the menu", placeholder: '' });
12
+ }
13
+ }
14
+ async function menuStep() {
15
+ const serverPath = await resolveServerDir();
16
+ const hasServer = serverPath !== null;
17
+ const pid = await loadPid();
18
+ const running = pid !== null && isAlive(pid.pid);
19
+ intro(c.green(`⚡ ${"PowerNukkitX Menu"}`));
20
+ if (running)
21
+ log.info(`Server running (PID ${String(pid.pid)})`);
22
+ else if (hasServer)
23
+ log.info("Server stopped");
24
+ else
25
+ log.warn("No server detected");
26
+ const options = [];
27
+ if (!hasServer)
28
+ options.push({ value: 'create', label: "Create a server" });
29
+ if (hasServer && !running)
30
+ options.push({ value: 'start', label: "Start the server" });
31
+ if (running)
32
+ options.push({ value: 'stop', label: "Stop the server" });
33
+ if (hasServer) {
34
+ options.push({ value: 'plugins', label: "Manage plugins" });
35
+ options.push({ value: 'install', label: "Install a plugin" });
36
+ options.push({ value: 'update', label: "Update the core" });
37
+ options.push({ value: 'backup', label: "Backup" });
38
+ }
39
+ options.push({ value: 'doctor', label: "Diagnostics" });
40
+ options.push({ value: 'info', label: "Information" });
41
+ options.push({ value: 'quit', label: "Quit" });
42
+ const choice = await promptSelect("What do you want to do?", options);
43
+ switch (choice) {
44
+ case 'create': {
45
+ const { initCmd } = await import('./init.js');
46
+ await initCmd.run({ args: {} });
47
+ break;
48
+ }
49
+ case 'start': {
50
+ const { runStart } = await import('./start.js');
51
+ await runStart({});
52
+ break;
53
+ }
54
+ case 'stop': {
55
+ const { runStop } = await import('./stop.js');
56
+ await runStop();
57
+ break;
58
+ }
59
+ case 'plugins': {
60
+ const { installCmd } = await import('./plugin/install.js');
61
+ await installCmd.run({ args: {} });
62
+ break;
63
+ }
64
+ case 'install': {
65
+ const { runInstall } = await import('./install.js');
66
+ await runInstall();
67
+ break;
68
+ }
69
+ case 'update': {
70
+ const { runUpdate } = await import('./update.js');
71
+ await runUpdate();
72
+ break;
73
+ }
74
+ case 'backup': {
75
+ const { runBackup } = await import('./backup.js');
76
+ await runBackup();
77
+ break;
78
+ }
79
+ case 'doctor': {
80
+ const { doctorCmd } = await import('./doctor.js');
81
+ await doctorCmd.run({ args: {} });
82
+ break;
83
+ }
84
+ case 'info': {
85
+ const { infoCmd } = await import('./info.js');
86
+ await infoCmd.run({ args: {} });
87
+ break;
88
+ }
89
+ case 'quit':
90
+ outro("See you soon!");
91
+ return true;
92
+ }
93
+ return false;
94
+ }
@@ -1,2 +1,2 @@
1
- import type { CommandDef } from 'citty';
2
- export declare const pluginCmd: CommandDef;
1
+ import type { CommandDef } from 'citty';
2
+ export declare const pluginCmd: CommandDef;