@powernukkitx/cli 0.0.3 → 1.0.1

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 (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -101
  3. package/dist/cli.js +34 -0
  4. package/dist/commands/backup.d.ts +2 -1
  5. package/dist/commands/backup.js +23 -74
  6. package/dist/commands/config.d.ts +1 -1
  7. package/dist/commands/config.js +60 -114
  8. package/dist/commands/console.d.ts +2 -0
  9. package/dist/commands/console.js +98 -0
  10. package/dist/commands/doctor.d.ts +2 -1
  11. package/dist/commands/doctor.js +97 -119
  12. package/dist/commands/info.d.ts +2 -1
  13. package/dist/commands/info.js +41 -36
  14. package/dist/commands/init.d.ts +2 -4
  15. package/dist/commands/init.js +87 -73
  16. package/dist/commands/install.js +45 -0
  17. package/dist/commands/logs.d.ts +2 -0
  18. package/dist/commands/logs.js +60 -0
  19. package/dist/commands/menu.js +94 -0
  20. package/dist/commands/plugin/index.d.ts +2 -0
  21. package/dist/commands/plugin/index.js +13 -0
  22. package/dist/commands/plugin/info.d.ts +2 -0
  23. package/dist/commands/plugin/info.js +39 -0
  24. package/dist/commands/plugin/install.d.ts +2 -0
  25. package/dist/commands/plugin/install.js +56 -0
  26. package/dist/commands/plugin/installed.d.ts +2 -0
  27. package/dist/commands/plugin/installed.js +41 -0
  28. package/dist/commands/plugin/list.d.ts +2 -0
  29. package/dist/commands/plugin/list.js +47 -0
  30. package/dist/commands/plugin/remove.d.ts +2 -0
  31. package/dist/commands/plugin/remove.js +44 -0
  32. package/dist/commands/plugin/search.d.ts +2 -0
  33. package/dist/commands/plugin/search.js +11 -0
  34. package/dist/commands/plugin/update.d.ts +2 -0
  35. package/dist/commands/plugin/update.js +52 -0
  36. package/dist/commands/start.d.ts +2 -7
  37. package/dist/commands/start.js +74 -108
  38. package/dist/commands/stop.d.ts +2 -0
  39. package/dist/commands/stop.js +26 -0
  40. package/dist/commands/update.d.ts +2 -5
  41. package/dist/commands/update.js +34 -55
  42. package/dist/commands/use.d.ts +2 -0
  43. package/dist/commands/use.js +39 -0
  44. package/dist/infra/http.js +119 -0
  45. package/dist/infra/paths.js +15 -0
  46. package/dist/infra/store.js +24 -0
  47. package/dist/services/backup.js +34 -0
  48. package/dist/services/plugins.js +139 -0
  49. package/dist/services/process.js +41 -0
  50. package/dist/services/release.js +51 -0
  51. package/dist/services/server.js +81 -0
  52. package/dist/ui/output.js +67 -0
  53. package/dist/ui/prompts.js +26 -0
  54. package/dist/ui/theme.js +16 -0
  55. package/package.json +44 -63
  56. package/dist/bundle.js +0 -18871
  57. package/dist/commands/plugin.d.ts +0 -12
  58. package/dist/commands/plugin.js +0 -385
  59. package/dist/index.d.ts +0 -2
  60. package/dist/index.js +0 -260
  61. package/dist/lang/en.json +0 -178
  62. package/dist/lang/fr.json +0 -178
  63. package/dist/lang/index.d.ts +0 -7
  64. package/dist/lang/index.js +0 -83
  65. package/dist/plugins.json +0 -66
  66. package/dist/types.d.ts +0 -61
  67. package/dist/types.js +0 -1
  68. package/dist/utils/api.d.ts +0 -18
  69. package/dist/utils/api.js +0 -74
  70. package/dist/utils/github.d.ts +0 -27
  71. package/dist/utils/github.js +0 -187
  72. package/dist/utils/logger.d.ts +0 -15
  73. package/dist/utils/logger.js +0 -72
  74. package/dist/utils/pause.d.ts +0 -1
  75. package/dist/utils/pause.js +0 -6
  76. package/dist/utils/plugins.d.ts +0 -4
  77. package/dist/utils/plugins.js +0 -34
  78. package/dist/utils/server.d.ts +0 -3
  79. package/dist/utils/server.js +0 -39
  80. package/dist/utils/updater.d.ts +0 -1
  81. package/dist/utils/updater.js +0 -86
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AzaleeX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,177 +1,186 @@
1
1
  # pnx-cli
2
2
 
3
- PowerNukkitX CLI est un outil en ligne de commande pour gérer un serveur **Minecraft Bedrock** propulsé par **PowerNukkitX**.
3
+ **PowerNukkitX CLI** - command line tool to manage a **Minecraft Bedrock** server powered by [PowerNukkitX](https://github.com/PowerNukkitX/PowerNukkitX).
4
4
 
5
- Il propose un menu interactif, la gestion des plugins, des outils de diagnostic, des sauvegardes, et des commandes rapides pour initialiser ou démarrer un serveur.
5
+ Create, start, update and diagnose your server, manage plugins from the marketplace, all with a clean interface and an interactive menu.
6
+
7
+ ## Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Requirements](#requirements)
11
+ - [Quick start](#quick-start)
12
+ - [Commands](#commands)
13
+ - [Interactive mode](#interactive-mode)
14
+ - [Global options](#global-options)
15
+ - [Architecture](#architecture)
16
+ - [Development](#development)
17
+ - [Links](#links)
18
+ - [License](#license)
6
19
 
7
20
  ## Installation
8
21
 
9
22
  ```bash
10
- npm install -g pnx-cli
23
+ npm install -g @powernukkitx/cli
11
24
  ```
12
25
 
13
- Après installation, la commande disponible est `pnx`.
26
+ The `pnx` command becomes available.
14
27
 
15
- ## Prérequis
28
+ ## Requirements
16
29
 
17
- - [Node.js](https://nodejs.org/) **18 ou plus**
18
- - Un dossier de serveur PowerNukkitX si vous souhaitez gérer une installation existante
30
+ - **Node.js 20.12+**
31
+ - **Java 21+** to run the server ([Adoptium Temurin](https://adoptium.net/) recommended)
19
32
 
20
- ## Démarrage rapide
21
-
22
- Lancer le menu interactif :
33
+ ## Quick start
23
34
 
24
35
  ```bash
36
+ # Contextual interactive menu
25
37
  pnx
26
- ```
27
38
 
28
- Afficher l’aide :
39
+ # Create a server then start it
40
+ pnx init --dir ./pnx-server
41
+ pnx start --memory 4G
29
42
 
30
- ```bash
43
+ # Help
31
44
  pnx --help
45
+ pnx <command> --help
32
46
  ```
33
47
 
34
- Choisir la langue :
35
-
36
- ```bash
37
- pnx --lang fr
38
- ```
39
-
40
- ## Fonctionnalités
41
-
42
- - Initialiser un nouveau serveur PowerNukkitX
43
- - Démarrer le serveur avec options de mémoire et redémarrage automatique
44
- - Installer, lister, rechercher, mettre à jour et supprimer des plugins
45
- - Vérifier l’état du serveur avec un diagnostic intégré
46
- - Créer des sauvegardes du serveur
47
- - Consulter la configuration et les informations du serveur
48
- - Mettre à jour `powernukkitx.jar`
49
- - Utiliser l’interface en anglais ou en français
48
+ ## Commands
50
49
 
51
- ## Commandes disponibles
50
+ ### `init` - create a server
52
51
 
53
- ### Initialiser un serveur
52
+ Downloads the latest `powernukkitx.jar` and the start scripts.
54
53
 
55
54
  ```bash
56
55
  pnx init --dir ./pnx-server
57
56
  ```
58
57
 
59
- Options :
58
+ | Option | Description |
59
+ |---|---|
60
+ | `--dir <path>` | Target directory (prompted otherwise) |
61
+ | `--dev` | Development build |
60
62
 
61
- - `-d, --dir <path>` : dossier cible
62
- - `--dev` : installer la version de développement
63
+ ### `start` - start the server
63
64
 
64
- ### Démarrer le serveur
65
+ Checks Java, builds optimized JVM arguments (generational ZGC, UTF-8) and launches the server.
65
66
 
66
67
  ```bash
67
68
  pnx start --memory 4G --restart
68
69
  ```
69
70
 
70
- Options :
71
+ | Option | Description |
72
+ |---|---|
73
+ | `--dir <path>` | Server directory |
74
+ | `--memory <size>` | Allocated memory, e.g. `2G`, `4G` (default `2G`) |
75
+ | `--restart` | Auto restart on crash |
76
+ | `--dry-run` | Print the command without running it |
71
77
 
72
- - `-g, --generate-only` : générer la commande de démarrage sans l’exécuter
73
- - `-r, --restart` : redémarrer automatiquement en cas de crash
74
- - `-m, --memory <size>` : mémoire allouée, par exemple `2G` ou `4G`
75
- - `-i, --interactive` : mode interactif avec prompts
78
+ ### `stop` - stop the server
76
79
 
77
- ### Gérer les plugins
80
+ Stops the server started through its stored PID.
78
81
 
79
82
  ```bash
80
- pnx plugin list
81
- pnx plugin search essentials
82
- pnx plugin info <slug>
83
- pnx plugin install <name>
84
- pnx plugin update
85
- pnx plugin remove <name>
86
- pnx plugin installed
83
+ pnx stop
87
84
  ```
88
85
 
89
- Sous-commandes :
86
+ ### `update` - update the core
90
87
 
91
- - `install [names...]` : installer un plugin depuis le marketplace ou une URL `.jar`
92
- - `list` : afficher les plugins disponibles
93
- - `search [term]` : rechercher par nom, description ou auteur
94
- - `info [slug]` : afficher la fiche détaillée d’un plugin
95
- - `installed` : lister les plugins installés localement
96
- - `update [names...]` : mettre à jour les plugins installés
97
- - `remove [names...]` : supprimer des plugins installés
98
-
99
- ### Mettre à jour le serveur
88
+ Backs up the old jar as `.old` then downloads the latest version.
100
89
 
101
90
  ```bash
102
91
  pnx update --force
103
92
  ```
104
93
 
105
- Options :
94
+ | Option | Description |
95
+ |---|---|
96
+ | `--force` | Force re-download (ignore cache) |
97
+ | `--dev` | Development build |
106
98
 
107
- - `--dev` : installer la version de développement
108
- - `-f, --force` : forcer la mise à jour même si la version correspond
99
+ ### `plugin` - manage plugins
109
100
 
110
- ### Diagnostics et utilitaires
101
+ Official marketplace plus local tracking of installed versions.
111
102
 
112
103
  ```bash
113
- pnx doctor
114
- pnx backup
115
- pnx config
116
- pnx info
117
- pnx lang --set fr
104
+ pnx plugin list # catalog
105
+ pnx plugin search essentials # search
106
+ pnx plugin info <slug> # details
107
+ pnx plugin install <slug|url.jar> # install (marketplace or .jar URL)
108
+ pnx plugin installed # local plugins
109
+ pnx plugin update [slug] # update
110
+ pnx plugin remove [name] # remove
118
111
  ```
119
112
 
120
- ## Mode interactif
113
+ Without an argument, `install`, `update` and `remove` offer an interactive selection.
121
114
 
122
- Si vous lancez `pnx` sans sous-commande, l’application ouvre un menu interactif pour :
115
+ ### Diagnostics and utilities
123
116
 
124
- - créer ou initialiser un serveur
125
- - démarrer le serveur
126
- - gérer les plugins
127
- - mettre à jour PowerNukkitX
128
- - lancer un diagnostic
129
- - effectuer une sauvegarde
130
- - changer la langue
117
+ ```bash
118
+ pnx doctor # Java, RAM, disk, port 19132, plugins/worlds
119
+ pnx info # status, path, plugins, worlds, RAM
120
+ pnx backup # timestamped server backup
121
+ pnx config # print pnx.yml / server.properties (colored)
122
+ pnx use ./server # set the default server
123
+ pnx logs # latest logs (with live follow)
124
+ pnx console # RCON console attached to the server
125
+ ```
131
126
 
132
- ## Développement
127
+ `doctor` and `info` accept `--json` for machine output.
133
128
 
134
- Installer les dépendances :
129
+ ## Interactive mode
135
130
 
136
- ```bash
137
- npm install
138
- ```
131
+ Launched without a subcommand, `pnx` opens a **contextual menu** that:
139
132
 
140
- Compiler le projet :
133
+ - detects state (server present, running, PID);
134
+ - only offers relevant actions (create if missing, start if stopped, stop if running...);
135
+ - routes to the existing commands.
141
136
 
142
137
  ```bash
143
- npm run build
138
+ pnx
144
139
  ```
145
140
 
146
- Lancer la CLI localement :
141
+ ## Global options
147
142
 
148
- ```bash
149
- npm start
150
- ```
143
+ | Option | Description |
144
+ |---|---|
145
+ | `--json` | Machine JSON output (disables decorative rendering) |
146
+ | `--no-color` | Disable colors |
151
147
 
152
- Surveiller les changements TypeScript :
148
+ CLI state is stored in `~/.pnx-cli/` (config, PID, installed plugins, version cache). Environment variables: `PNX_API_URL` (marketplace API base), `PNX_HOME` (state directory).
153
149
 
154
- ```bash
155
- npm run dev
150
+ ## Architecture
151
+
152
+ The code follows a layered architecture - thin commands, isolated business logic:
153
+
154
+ ```
155
+ dist/
156
+ cli.js entry point (citty) + global options
157
+ commands/ parse arguments -> call service -> render
158
+ plugin/ plugin subcommands
159
+ services/ pure business logic (release, server, process, plugins, backup)
160
+ infra/ http, JSON store (~/.pnx-cli), constants/endpoints
161
+ ui/ single output system (clack + chalk), prompts
156
162
  ```
157
163
 
158
- ## Exécutables autonomes
164
+ Rules: commands do no direct network/file access (everything goes through `services`/`infra`); services render nothing (they return data).
165
+
166
+ **Stack**: [citty](https://github.com/unjs/citty) (routing), [@clack/prompts](https://github.com/bombshell-dev/clack) (prompts), [chalk](https://github.com/chalk/chalk) (colors).
159
167
 
160
- Le projet fournit aussi des scripts pour générer des exécutables Windows, Linux et macOS :
168
+ ## Development
169
+
170
+ The shipped code lives in `dist/` (plain ES modules, no build step).
161
171
 
162
172
  ```bash
163
- npm run build:exe:win
164
- npm run build:exe:linux
165
- npm run build:exe:mac
173
+ npm install # dependencies
174
+ npm start # run dist/cli.js
175
+ npm run check # syntax check every file
176
+ npm run smoke # run pnx --help
166
177
  ```
167
178
 
168
- ## Liens utiles
179
+ ## Links
169
180
 
170
- - Documentation PowerNukkitX : https://docs.powernukkitx.org
171
- - Dépôt PowerNukkitX : https://github.com/PowerNukkitX/PowerNukkitX
181
+ - PowerNukkitX documentation: https://docs.powernukkitx.org
182
+ - PowerNukkitX repository: https://github.com/PowerNukkitX/PowerNukkitX
172
183
 
173
- ## Licence
184
+ ## License
174
185
 
175
186
  MIT
176
-
177
-
package/dist/cli.js ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ import { defineCommand, runMain } from 'citty';
3
+ import { setColorEnabled } from './ui/theme.js';
4
+ if (process.argv.slice(2).includes('--no-color'))
5
+ setColorEnabled(false);
6
+ const main = defineCommand({
7
+ meta: {
8
+ name: 'pnx',
9
+ version: '1.0.0',
10
+ description: 'PowerNukkitX CLI — Manage your Minecraft Bedrock servers',
11
+ },
12
+ subCommands: {
13
+ init: () => import('./commands/init.js').then(m => m.initCmd),
14
+ install: () => import('./commands/install.js').then(m => m.installCmd),
15
+ start: () => import('./commands/start.js').then(m => m.startCmd),
16
+ stop: () => import('./commands/stop.js').then(m => m.stopCmd),
17
+ update: () => import('./commands/update.js').then(m => m.updateCmd),
18
+ info: () => import('./commands/info.js').then(m => m.infoCmd),
19
+ doctor: () => import('./commands/doctor.js').then(m => m.doctorCmd),
20
+ backup: () => import('./commands/backup.js').then(m => m.backupCmd),
21
+ config: () => import('./commands/config.js').then(m => m.configCmd),
22
+ use: () => import('./commands/use.js').then(m => m.useCmd),
23
+ logs: () => import('./commands/logs.js').then(m => m.logsCmd),
24
+ console: () => import('./commands/console.js').then(m => m.consoleCmd),
25
+ plugin: () => import('./commands/plugin/index.js').then(m => m.pluginCmd),
26
+ },
27
+ async run({ args }) {
28
+ if (args._.length === 0) {
29
+ const { runMenu } = await import('./commands/menu.js');
30
+ await runMenu();
31
+ }
32
+ },
33
+ });
34
+ runMain(main);
@@ -1 +1,2 @@
1
- export declare function backupCmd(): Promise<void>;
1
+ import type { CommandDef } from 'citty';
2
+ export declare const backupCmd: CommandDef;
@@ -1,74 +1,23 @@
1
- import { readdirSync, statSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { mkdir, cp, readdir } from 'node:fs/promises';
4
- import { cwd } from 'node:process';
5
- import { confirm } from '@inquirer/prompts';
6
- import { header, success, error, info, highlight, step } from '../utils/logger.js';
7
- import { t } from '../lang/index.js';
8
- import { resolveServerDir } from '../utils/server.js';
9
- import { pauseForExit } from '../utils/pause.js';
10
- const IGNORE = new Set(['logs', 'cache', 'crash-reports', 'backups', 'powernukkitx.jar.old']);
11
- function getDirSize(dir) {
12
- let total = 0;
13
- try {
14
- const items = readdirSync(dir);
15
- for (const item of items) {
16
- const full = join(dir, item);
17
- const s = statSync(full);
18
- if (s.isDirectory())
19
- total += getDirSize(full);
20
- else
21
- total += s.size;
22
- }
23
- }
24
- catch { /* ignore */ }
25
- return total;
26
- }
27
- function formatSize(bytes) {
28
- if (bytes < 1024)
29
- return `${bytes} B`;
30
- if (bytes < 1024 * 1024)
31
- return `${(bytes / 1024).toFixed(1)} KB`;
32
- return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
33
- }
34
- export async function backupCmd() {
35
- const serverPath = await resolveServerDir(t('backup.selectServer'));
36
- if (!serverPath) {
37
- error(t('backup.noServer'));
38
- await pauseForExit();
39
- return;
40
- }
41
- if (serverPath === cwd()) {
42
- const ok = await confirm({
43
- message: t('backup.backupCurrent', highlight(serverPath)),
44
- default: true,
45
- });
46
- if (!ok) {
47
- info(t('backup.cancelled'));
48
- await pauseForExit();
49
- return;
50
- }
51
- }
52
- header(`💾 ${t('backup.title')}`);
53
- step(t('backup.collecting'));
54
- const size = getDirSize(serverPath);
55
- info(t('backup.estimatedSize', formatSize(size)));
56
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
57
- const backupDir = join(serverPath, 'backups');
58
- const destDir = join(backupDir, `pnx-backup-${timestamp}`);
59
- await mkdir(destDir, { recursive: true });
60
- step(t('backup.copying'));
61
- const items = await readdir(serverPath);
62
- let count = 0;
63
- for (const item of items) {
64
- if (IGNORE.has(item) || item.startsWith('.'))
65
- continue;
66
- const src = join(serverPath, item);
67
- const dst = join(destDir, item);
68
- await cp(src, dst, { recursive: true, force: true });
69
- count++;
70
- }
71
- const finalSize = getDirSize(destDir);
72
- success(t('backup.done', destDir, formatSize(finalSize)));
73
- await pauseForExit();
74
- }
1
+ import { defineCommand } from 'citty';
2
+ import { intro, outro, log, spin } from '../ui/output.js';
3
+ import { resolveServerDir } from '../services/server.js';
4
+ import { createBackup, dirSize, fmtSize } from '../services/backup.js';
5
+ export async function runBackup() {
6
+ intro(`💾 ${"Backup"}`);
7
+ const serverPath = await resolveServerDir();
8
+ if (!serverPath) {
9
+ log.error("No server detected");
10
+ process.exit(1);
11
+ }
12
+ const sp = spin("Collecting files...");
13
+ sp.stop(`Estimated size: ${fmtSize(dirSize(serverPath))}`);
14
+ const sp2 = spin("Copying files...");
15
+ const { path, size } = await createBackup(serverPath);
16
+ sp2.stop(`Backup created: ${path} (${fmtSize(size)})`);
17
+ outro(`Backup created: ${path} (${fmtSize(size)})`);
18
+ }
19
+ export const backupCmd = defineCommand({
20
+ meta: { description: 'Create a server backup' },
21
+ args: {},
22
+ run: () => runBackup(),
23
+ });
@@ -1 +1 @@
1
- export declare function configCmd(): Promise<void>;
1
+ export declare function configCmd(): Promise<void>;
@@ -1,114 +1,60 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import chalk from 'chalk';
4
- import { header, error, info, highlight, dim } from '../utils/logger.js';
5
- import { t } from '../lang/index.js';
6
- import { resolveServerDir } from '../utils/server.js';
7
- import { pauseForExit } from '../utils/pause.js';
8
- export async function configCmd() {
9
- const serverPath = await resolveServerDir();
10
- if (!serverPath) {
11
- error(t('config.noServer'));
12
- info(t('config.hintInit'));
13
- await pauseForExit();
14
- return;
15
- }
16
- // Prefer pnx.yml, fallback to server.properties
17
- let configPath = join(serverPath, 'pnx.yml');
18
- if (!existsSync(configPath)) {
19
- configPath = join(serverPath, 'server.properties');
20
- if (!existsSync(configPath)) {
21
- error(t('config.notFound'));
22
- info(t('config.hintGenerate'));
23
- await pauseForExit();
24
- return;
25
- }
26
- }
27
- const isYml = configPath.endsWith('.yml');
28
- header(`⚙️ ${t('config.title')} ${dim(isYml ? '(pnx.yml)' : '(server.properties)')}`);
29
- let content = readFileSync(configPath, 'utf-8');
30
- // Strip BOM
31
- if (content.charCodeAt(0) === 0xFEFF)
32
- content = content.slice(1);
33
- const lines = content.split('\n');
34
- if (isYml) {
35
- // Display YAML with syntax highlighting
36
- for (let i = 0; i < lines.length; i++) {
37
- const line = lines[i];
38
- if (line.trim() === '' || line.trim().startsWith('#')) {
39
- if (line.trim().startsWith('#')) {
40
- console.log(` ${dim(line)}`);
41
- }
42
- else {
43
- console.log();
44
- }
45
- continue;
46
- }
47
- // Key: value or nested key
48
- const indent = line.match(/^(\s*)/)?.[1] || '';
49
- const trimmed = line.trim();
50
- const colonIdx = trimmed.indexOf(':');
51
- if (colonIdx > 0) {
52
- const key = trimmed.slice(0, colonIdx);
53
- const rest = trimmed.slice(colonIdx + 1).trim();
54
- const suffix = rest
55
- ? ` ${colorYamlValue(rest)}`
56
- : '';
57
- const prefix = indent ? chalk.dim(indent) : '';
58
- console.log(` ${prefix}${chalk.hex('#6C8EBF')(key)}:${suffix}`);
59
- }
60
- else {
61
- console.log(` ${chalk.dim(indent)}${chalk.white(trimmed)}`);
62
- }
63
- }
64
- }
65
- else {
66
- // Display server.properties with highlighting
67
- let inSection = false;
68
- for (let i = 0; i < lines.length; i++) {
69
- const line = lines[i];
70
- if (line.startsWith('#') || line.trim() === '') {
71
- const trimmed = line.replace(/^#\s*/, '').trim();
72
- if (trimmed && !inSection) {
73
- console.log(`\n ${dim(trimmed)}`);
74
- inSection = true;
75
- }
76
- continue;
77
- }
78
- inSection = false;
79
- const eqIdx = line.indexOf('=');
80
- if (eqIdx > 0) {
81
- const key = line.slice(0, eqIdx).trim();
82
- const value = line.slice(eqIdx + 1).trim();
83
- console.log(` ${highlight(key)} ${dim('=')} ${colorPropsValue(value)}`);
84
- }
85
- }
86
- }
87
- console.log(`\n ${dim('─'.repeat(40))}`);
88
- info(t('config.editHint', highlight(configPath)));
89
- await pauseForExit();
90
- }
91
- function colorYamlValue(val) {
92
- if (val === 'true')
93
- return chalk.green(val);
94
- if (val === 'false')
95
- return chalk.red(val);
96
- if (/^\d+(\.\d+)?$/.test(val))
97
- return chalk.cyan(val);
98
- if (val.startsWith('[') || val.startsWith('-'))
99
- return chalk.hex('#E040FB')(val);
100
- if (val.startsWith('"') && val.endsWith('"'))
101
- return chalk.green(val);
102
- if (val.startsWith("'") && val.endsWith("'"))
103
- return chalk.green(val);
104
- return chalk.white(val);
105
- }
106
- function colorPropsValue(val) {
107
- if (val === 'true' || val === 'on')
108
- return chalk.green(val);
109
- if (val === 'false' || val === 'off')
110
- return chalk.red(val);
111
- if (/^\d+$/.test(val))
112
- return chalk.cyan(val);
113
- return chalk.white(val);
114
- }
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { defineCommand } from 'citty';
4
+ import { intro, outro, log } from '../ui/output.js';
5
+ import { c } from '../ui/theme.js';
6
+ import { resolveServerDir } from '../services/server.js';
7
+ function colorVal(val) {
8
+ if (val === 'true' || val === 'on')
9
+ return c.green(val);
10
+ if (val === 'false' || val === 'off')
11
+ return c.red(val);
12
+ if (/^\d+(\.\d+)?$/.test(val))
13
+ return c.cyan(val);
14
+ return val;
15
+ }
16
+ export const configCmd = defineCommand({
17
+ meta: { description: 'View server configuration' },
18
+ args: {},
19
+ async run() {
20
+ intro(`⚙️ ${"Configuration"}`);
21
+ const serverPath = await resolveServerDir();
22
+ if (!serverPath) {
23
+ log.error("No server detected");
24
+ process.exit(1);
25
+ }
26
+ let cfgPath = join(serverPath, 'pnx.yml');
27
+ if (!existsSync(cfgPath))
28
+ cfgPath = join(serverPath, 'server.properties');
29
+ if (!existsSync(cfgPath)) {
30
+ log.error("No config file found");
31
+ process.exit(1);
32
+ }
33
+ let content = readFileSync(cfgPath, 'utf-8');
34
+ if (content.charCodeAt(0) === 0xfeff)
35
+ content = content.slice(1);
36
+ const sep = cfgPath.endsWith('.yml') ? ':' : '=';
37
+ for (const line of content.split('\n')) {
38
+ const trimmed = line.trim();
39
+ if (!trimmed) {
40
+ log.raw('');
41
+ continue;
42
+ }
43
+ if (trimmed.startsWith('#')) {
44
+ log.raw(` ${c.dim(line)}`);
45
+ continue;
46
+ }
47
+ const idx = trimmed.indexOf(sep);
48
+ if (idx > 0) {
49
+ const key = trimmed.slice(0, idx);
50
+ const val = trimmed.slice(idx + 1).trim();
51
+ const indent = line.match(/^(\s*)/)?.[1] ?? '';
52
+ log.raw(` ${indent}${c.blue(key)}${sep}${val ? ' ' + colorVal(val) : ''}`);
53
+ }
54
+ else
55
+ log.raw(` ${c.dim(trimmed)}`);
56
+ }
57
+ log.info(`Edit ${cfgPath} to change these values`);
58
+ outro('');
59
+ },
60
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandDef } from 'citty';
2
+ export declare const consoleCmd: CommandDef;