@powernukkitx/cli 0.0.3 → 1.0.0
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/README.md +203 -177
- package/dist/bundle.js +3 -18856
- package/dist/cli.js +46 -0
- package/dist/commands/backup.d.ts +2 -1
- package/dist/commands/backup.js +21 -71
- package/dist/commands/cfg.d.ts +2 -0
- package/dist/commands/cfg.js +61 -0
- package/dist/commands/config.js +52 -105
- package/dist/commands/console.d.ts +2 -0
- package/dist/commands/console.js +99 -0
- package/dist/commands/doctor.d.ts +2 -1
- package/dist/commands/doctor.js +87 -108
- package/dist/commands/info.d.ts +2 -1
- package/dist/commands/info.js +39 -33
- package/dist/commands/init.d.ts +2 -4
- package/dist/commands/init.js +58 -65
- package/dist/commands/lang.d.ts +2 -0
- package/dist/commands/lang.js +28 -0
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +61 -0
- package/dist/commands/menu.js +86 -0
- package/dist/commands/plugin/index.d.ts +2 -0
- package/dist/commands/plugin/index.js +13 -0
- package/dist/commands/plugin/info.d.ts +2 -0
- package/dist/commands/plugin/info.js +40 -0
- package/dist/commands/plugin/install.d.ts +2 -0
- package/dist/commands/plugin/install.js +57 -0
- package/dist/commands/plugin/installed.d.ts +2 -0
- package/dist/commands/plugin/installed.js +42 -0
- package/dist/commands/plugin/list.d.ts +2 -0
- package/dist/commands/plugin/list.js +49 -0
- package/dist/commands/plugin/remove.d.ts +2 -0
- package/dist/commands/plugin/remove.js +45 -0
- package/dist/commands/plugin/search.d.ts +2 -0
- package/dist/commands/plugin/search.js +12 -0
- package/dist/commands/plugin/update.d.ts +2 -0
- package/dist/commands/plugin/update.js +53 -0
- package/dist/commands/plugin.d.ts +1 -12
- package/dist/commands/plugin.js +1 -385
- package/dist/commands/start.d.ts +2 -7
- package/dist/commands/start.js +61 -94
- package/dist/commands/stop.d.ts +2 -0
- package/dist/commands/stop.js +27 -0
- package/dist/commands/update.d.ts +2 -5
- package/dist/commands/update.js +30 -50
- package/dist/commands/use.d.ts +2 -0
- package/dist/commands/use.js +40 -0
- package/dist/core/config.d.ts +13 -0
- package/dist/core/config.js +31 -0
- package/dist/core/network.d.ts +13 -0
- package/dist/core/network.js +139 -0
- package/dist/core/output.d.ts +33 -0
- package/dist/core/output.js +75 -0
- package/dist/core/process.d.ts +10 -0
- package/dist/core/process.js +53 -0
- package/dist/i18n/en.json +174 -0
- package/dist/i18n/fr.json +174 -0
- package/dist/i18n/index.js +58 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -260
- package/dist/infra/http.js +121 -0
- package/dist/infra/paths.js +20 -0
- package/dist/infra/store.js +27 -0
- package/dist/lang/en.json +116 -148
- package/dist/lang/fr.json +115 -147
- package/dist/main.d.ts +2 -0
- package/dist/main.js +28 -0
- package/dist/services/backup.js +40 -0
- package/dist/services/plugins.js +111 -0
- package/dist/services/process.js +43 -0
- package/dist/services/release.js +38 -0
- package/dist/services/server.js +89 -0
- package/dist/ui/output.js +71 -0
- package/dist/ui/prompts.js +30 -0
- package/dist/ui/theme.js +18 -0
- package/dist/utils/api.d.ts +3 -12
- package/dist/utils/api.js +7 -57
- package/dist/utils/github.d.ts +3 -10
- package/dist/utils/github.js +27 -154
- package/dist/utils/server.d.ts +2 -2
- package/dist/utils/server.js +17 -24
- package/package.json +15 -32
package/dist/commands/plugin.js
CHANGED
|
@@ -1,385 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { readdir, mkdir, rm, rename as fsRename } from 'node:fs/promises';
|
|
3
|
-
import { join, resolve } from 'node:path';
|
|
4
|
-
import { checkbox, confirm, input, select } from '@inquirer/prompts';
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
import { header, success, error, info, warn, highlight, dim, step, bullet, divider } from '../utils/logger.js';
|
|
7
|
-
import { t } from '../lang/index.js';
|
|
8
|
-
import { fetchPluginsList, fetchPluginDetail, proxyDownloadUrl } from '../utils/api.js';
|
|
9
|
-
import { downloadFile } from '../utils/github.js';
|
|
10
|
-
import { saveInstalledPlugin, getInstalledPlugins } from '../utils/plugins.js';
|
|
11
|
-
import { resolveServerDir } from '../utils/server.js';
|
|
12
|
-
async function getPluginsDir() {
|
|
13
|
-
const server = await resolveServerDir();
|
|
14
|
-
return server ? join(server, 'plugins') : resolve('plugins');
|
|
15
|
-
}
|
|
16
|
-
function formatDownloads(n) {
|
|
17
|
-
if (n >= 1000)
|
|
18
|
-
return `${(n / 1000).toFixed(1)}k`;
|
|
19
|
-
return String(n);
|
|
20
|
-
}
|
|
21
|
-
function renderStars(n) {
|
|
22
|
-
const full = '★'.repeat(Math.min(Math.floor(n / 10), 5));
|
|
23
|
-
const empty = '☆'.repeat(Math.max(5 - full.length, 0));
|
|
24
|
-
const color = n >= 50 ? chalk.yellow : chalk.dim;
|
|
25
|
-
return color(full + empty);
|
|
26
|
-
}
|
|
27
|
-
// ─── List ─────────────────────────────────────────────────────
|
|
28
|
-
export async function pluginListCmd(options) {
|
|
29
|
-
header(`📋 ${t('plugin.titleList')}`);
|
|
30
|
-
const params = {};
|
|
31
|
-
if (options?.sort)
|
|
32
|
-
params.sort = options.sort;
|
|
33
|
-
if (options?.limit)
|
|
34
|
-
params.limit = options.limit;
|
|
35
|
-
if (options?.page)
|
|
36
|
-
params.page = options.page;
|
|
37
|
-
if (options?.q)
|
|
38
|
-
params.q = options.q;
|
|
39
|
-
step(t('plugin.fetching'));
|
|
40
|
-
try {
|
|
41
|
-
const resp = await fetchPluginsList(params);
|
|
42
|
-
const list = resp.plugins;
|
|
43
|
-
if (list.length === 0) {
|
|
44
|
-
info(t('plugin.catalogEmpty'));
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
for (const p of list) {
|
|
48
|
-
const name = chalk.hex('#FFB347')(p.name);
|
|
49
|
-
const author = chalk.dim(`by ${p.author}`);
|
|
50
|
-
const stars = renderStars(p.stars);
|
|
51
|
-
const downloads = chalk.cyan(`${formatDownloads(p.downloads)} downloads`);
|
|
52
|
-
const version = chalk.dim(`v${p.version}`);
|
|
53
|
-
const installCmd = chalk.hex('#6C8EBF')(`pnx plugin install ${p.slug}`);
|
|
54
|
-
console.log(` ${name} ${author} ${stars} ${downloads} ${version}`);
|
|
55
|
-
if (p.description) {
|
|
56
|
-
console.log(` ${chalk.dim(' ')}${p.description}`);
|
|
57
|
-
}
|
|
58
|
-
console.log(` ${chalk.dim(' →')} ${installCmd}\n`);
|
|
59
|
-
}
|
|
60
|
-
if (resp.count > list.length) {
|
|
61
|
-
info(t('plugin.showingCount', String(list.length), String(resp.count)));
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
catch (err) {
|
|
65
|
-
error(t('plugin.fetchError', err.message));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// ─── Search ───────────────────────────────────────────────────
|
|
69
|
-
export async function pluginSearchCmd(term) {
|
|
70
|
-
if (!term) {
|
|
71
|
-
term = await input({ message: t('plugin.searchPrompt'), default: '' });
|
|
72
|
-
if (!term) {
|
|
73
|
-
info(t('plugin.searchCancelled'));
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
await pluginListCmd({ q: term });
|
|
78
|
-
}
|
|
79
|
-
// ─── Info ─────────────────────────────────────────────────────
|
|
80
|
-
export async function pluginInfoCmd(slug) {
|
|
81
|
-
if (!slug) {
|
|
82
|
-
slug = await input({ message: t('plugin.infoPrompt'), default: '' });
|
|
83
|
-
if (!slug) {
|
|
84
|
-
info(t('plugin.infoCancelled'));
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
header(`📖 ${t('plugin.titleInfo')} — ${highlight(slug)}`);
|
|
89
|
-
step(t('plugin.fetching'));
|
|
90
|
-
try {
|
|
91
|
-
const detail = await fetchPluginDetail(slug);
|
|
92
|
-
const latest = detail.releases.find(r => r.is_stable) || detail.releases[0];
|
|
93
|
-
console.log(`\n ${chalk.hex('#FFB347').bold(detail.name)}`);
|
|
94
|
-
if (detail.description)
|
|
95
|
-
console.log(` ${dim(detail.description)}`);
|
|
96
|
-
console.log();
|
|
97
|
-
console.log(` ${dim('Author:')} ${highlight(detail.author)}`);
|
|
98
|
-
console.log(` ${dim('Stars:')} ${renderStars(detail.stars)} ${detail.stars}`);
|
|
99
|
-
console.log(` ${dim('Downloads:')} ${chalk.cyan(formatDownloads(detail.downloads))}`);
|
|
100
|
-
console.log(` ${dim('Version:')} ${chalk.green(detail.latest_version)}`);
|
|
101
|
-
console.log(` ${dim('Updated:')} ${dim(new Date(detail.updated_at).toLocaleDateString())}`);
|
|
102
|
-
console.log(` ${dim('Tags:')} ${(detail.tags || []).map(t => chalk.cyan(t)).join(', ')}`);
|
|
103
|
-
if (detail.repository_url)
|
|
104
|
-
console.log(` ${dim('Repo:')} ${chalk.blue(detail.repository_url)}`);
|
|
105
|
-
if (detail.documentation_url)
|
|
106
|
-
console.log(` ${dim('Docs:')} ${chalk.blue(detail.documentation_url)}`);
|
|
107
|
-
if (detail.license_url)
|
|
108
|
-
console.log(` ${dim('License:')} ${chalk.blue(detail.license_url)}`);
|
|
109
|
-
// Releases
|
|
110
|
-
if (detail.releases.length > 0) {
|
|
111
|
-
divider();
|
|
112
|
-
step(t('plugin.releases'));
|
|
113
|
-
for (const r of detail.releases.slice(0, 5)) {
|
|
114
|
-
const stable = r.is_stable ? chalk.green('●') : chalk.dim('○');
|
|
115
|
-
const fileInfo = r.files.length > 0
|
|
116
|
-
? `${chalk.cyan((r.files[0].size / 1024).toFixed(0) + ' KB')}`
|
|
117
|
-
: '';
|
|
118
|
-
console.log(` ${stable} ${chalk.bold('v' + r.version)} ${dim(new Date(r.created_at).toLocaleDateString())} ${fileInfo}`);
|
|
119
|
-
}
|
|
120
|
-
if (detail.releases.length > 5) {
|
|
121
|
-
info(t('plugin.moreReleases', String(detail.releases.length - 5)));
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (err) {
|
|
126
|
-
error(t('plugin.notFound', slug));
|
|
127
|
-
if (err.message)
|
|
128
|
-
warn(err.message);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
// ─── Install ──────────────────────────────────────────────────
|
|
132
|
-
async function pickVersion(releases) {
|
|
133
|
-
const choices = releases.map(r => ({
|
|
134
|
-
name: `${r.is_stable ? chalk.green('●') : chalk.dim('○')} v${r.version} ${dim(new Date(r.created_at).toLocaleDateString())} ${r.is_stable ? chalk.green('stable') : chalk.dim('dev')}`,
|
|
135
|
-
value: r,
|
|
136
|
-
}));
|
|
137
|
-
return await select({
|
|
138
|
-
message: t('plugin.selectVersion'),
|
|
139
|
-
choices,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
export async function pluginInstallCmd(names) {
|
|
143
|
-
const pluginsDir = await getPluginsDir();
|
|
144
|
-
await mkdir(pluginsDir, { recursive: true });
|
|
145
|
-
// interactive picker if no names
|
|
146
|
-
if (names.length === 0) {
|
|
147
|
-
header(`📦 ${t('plugin.titleInstall')}`);
|
|
148
|
-
step(t('plugin.fetching'));
|
|
149
|
-
try {
|
|
150
|
-
const resp = await fetchPluginsList({ sort: 'stars', limit: 50 });
|
|
151
|
-
const choices = resp.plugins.map(p => ({
|
|
152
|
-
name: `${chalk.hex('#FFB347')(p.name)} ${chalk.dim('—')} ${chalk.dim(p.description || '')}`,
|
|
153
|
-
value: p.slug,
|
|
154
|
-
}));
|
|
155
|
-
const selected = await checkbox({
|
|
156
|
-
message: t('plugin.selectPrompt'),
|
|
157
|
-
choices,
|
|
158
|
-
pageSize: 10,
|
|
159
|
-
});
|
|
160
|
-
names = selected;
|
|
161
|
-
if (names.length === 0) {
|
|
162
|
-
info(t('plugin.noSelection'));
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
catch (err) {
|
|
167
|
-
error(t('plugin.fetchError', err.message));
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
header(`📦 ${t('plugin.titleInstall')}`);
|
|
172
|
-
for (const slug of names) {
|
|
173
|
-
try {
|
|
174
|
-
step(t('plugin.fetchingInfo', slug));
|
|
175
|
-
// URL install
|
|
176
|
-
if (slug.startsWith('http://') || slug.startsWith('https://')) {
|
|
177
|
-
if (slug.endsWith('.jar')) {
|
|
178
|
-
const dest = join(pluginsDir, slug.split('/').pop() || 'plugin.jar');
|
|
179
|
-
await downloadFile(slug, dest, dest.split('/').pop() || 'plugin.jar');
|
|
180
|
-
success(t('plugin.installSuccess', slug.split('/').pop() || ''));
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
error(t('plugin.urlInvalid'));
|
|
184
|
-
}
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
const detail = await fetchPluginDetail(slug);
|
|
188
|
-
let release = detail.releases.find(r => r.is_stable) || detail.releases[0];
|
|
189
|
-
if (!release) {
|
|
190
|
-
error(t('plugin.noRelease', slug));
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
// Ask for version if multiple releases
|
|
194
|
-
if (detail.releases.length > 1) {
|
|
195
|
-
release = await pickVersion(detail.releases);
|
|
196
|
-
}
|
|
197
|
-
const file = release.files[0];
|
|
198
|
-
if (!file) {
|
|
199
|
-
error(t('plugin.noFile', slug, release.version));
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
// Download via proxy
|
|
203
|
-
const downloadUrl = proxyDownloadUrl(slug, release.version);
|
|
204
|
-
const dest = join(pluginsDir, file.name);
|
|
205
|
-
await downloadFile(downloadUrl, dest, file.name);
|
|
206
|
-
// Track installation
|
|
207
|
-
await saveInstalledPlugin({
|
|
208
|
-
slug,
|
|
209
|
-
name: detail.name,
|
|
210
|
-
version: release.version,
|
|
211
|
-
installedAt: new Date().toISOString(),
|
|
212
|
-
fileName: file.name,
|
|
213
|
-
});
|
|
214
|
-
success(t('plugin.installSuccess', detail.name));
|
|
215
|
-
}
|
|
216
|
-
catch (err) {
|
|
217
|
-
error(t('plugin.installError', slug));
|
|
218
|
-
if (err.message)
|
|
219
|
-
warn(err.message);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
// Summary
|
|
223
|
-
const jars = await getInstalledJars(pluginsDir);
|
|
224
|
-
if (jars.length > 0) {
|
|
225
|
-
console.log();
|
|
226
|
-
info(t('plugin.installedCount', String(jars.length)));
|
|
227
|
-
info(t('plugin.restartHint'));
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
// ─── Installed ────────────────────────────────────────────────
|
|
231
|
-
async function getInstalledJars(dir) {
|
|
232
|
-
if (!existsSync(dir))
|
|
233
|
-
return [];
|
|
234
|
-
const files = await readdir(dir);
|
|
235
|
-
return files.filter(f => f.endsWith('.jar'));
|
|
236
|
-
}
|
|
237
|
-
export async function pluginInstalledCmd() {
|
|
238
|
-
const pluginsDir = await getPluginsDir();
|
|
239
|
-
header(`📁 ${t('plugin.titleInstalled')}`);
|
|
240
|
-
if (!existsSync(pluginsDir)) {
|
|
241
|
-
info(t('plugin.noPluginsDir'));
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
const jars = await getInstalledJars(pluginsDir);
|
|
245
|
-
if (jars.length === 0) {
|
|
246
|
-
info(t('plugin.noPlugins'));
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
const tracked = await getInstalledPlugins();
|
|
250
|
-
bullet(jars.map((j) => {
|
|
251
|
-
const slug = j.replace('.jar', '');
|
|
252
|
-
const meta = tracked.find(p => p.fileName === j || p.slug === slug);
|
|
253
|
-
if (meta) {
|
|
254
|
-
return `${highlight(slug)} ${dim('v' + meta.version)}`;
|
|
255
|
-
}
|
|
256
|
-
return highlight(slug);
|
|
257
|
-
}));
|
|
258
|
-
console.log();
|
|
259
|
-
info(t('plugin.installedCount', String(jars.length)));
|
|
260
|
-
info(t('plugin.restartHint'));
|
|
261
|
-
}
|
|
262
|
-
// ─── Remove ───────────────────────────────────────────────────
|
|
263
|
-
export async function pluginRemoveCmd(names) {
|
|
264
|
-
const pluginsDir = await getPluginsDir();
|
|
265
|
-
header(`🗑️ ${t('plugin.titleRemove')}`);
|
|
266
|
-
if (!existsSync(pluginsDir)) {
|
|
267
|
-
error(t('plugin.noPluginsDir'));
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
const jars = await getInstalledJars(pluginsDir);
|
|
271
|
-
if (names.length === 0) {
|
|
272
|
-
const choices = jars.map(j => ({
|
|
273
|
-
name: highlight(j.replace('.jar', '')),
|
|
274
|
-
value: j,
|
|
275
|
-
}));
|
|
276
|
-
if (choices.length === 0) {
|
|
277
|
-
info(t('plugin.noPlugins'));
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
const selected = await checkbox({ message: t('plugin.removePrompt'), choices });
|
|
281
|
-
names = selected;
|
|
282
|
-
if (names.length === 0) {
|
|
283
|
-
info(t('plugin.noSelection'));
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
for (const rawName of names) {
|
|
288
|
-
const target = rawName.endsWith('.jar') ? rawName : `${rawName}.jar`;
|
|
289
|
-
const found = jars.find(j => j.toLowerCase() === target.toLowerCase());
|
|
290
|
-
if (!found) {
|
|
291
|
-
warn(t('plugin.notFound', rawName));
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
const ok = await confirm({ message: t('plugin.removeConfirm', found), default: false });
|
|
295
|
-
if (ok) {
|
|
296
|
-
await rm(join(pluginsDir, found));
|
|
297
|
-
success(t('plugin.removed', found));
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
info(t('plugin.removeCancelled', found));
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
// ─── Update ───────────────────────────────────────────────────
|
|
305
|
-
export async function pluginUpdateCmd(names) {
|
|
306
|
-
const pluginsDir = await getPluginsDir();
|
|
307
|
-
header(`🔄 ${t('plugin.titleUpdate')}`);
|
|
308
|
-
if (!existsSync(pluginsDir)) {
|
|
309
|
-
error(t('plugin.noPluginsDir'));
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
const jars = await getInstalledJars(pluginsDir);
|
|
313
|
-
if (jars.length === 0) {
|
|
314
|
-
info(t('plugin.noPlugins'));
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
// interactive picker if no names
|
|
318
|
-
if (names.length === 0) {
|
|
319
|
-
const choices = jars.map(j => ({
|
|
320
|
-
name: highlight(j.replace('.jar', '')),
|
|
321
|
-
value: j,
|
|
322
|
-
}));
|
|
323
|
-
const selected = await checkbox({
|
|
324
|
-
message: t('plugin.updateSelect'),
|
|
325
|
-
choices,
|
|
326
|
-
});
|
|
327
|
-
names = selected.map(n => n.replace('.jar', ''));
|
|
328
|
-
if (names.length === 0) {
|
|
329
|
-
info(t('plugin.noSelection'));
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
for (const rawName of names) {
|
|
334
|
-
const slug = rawName.endsWith('.jar') ? rawName.replace('.jar', '') : rawName;
|
|
335
|
-
const jarFile = jars.find(j => j.toLowerCase().startsWith(slug.toLowerCase()));
|
|
336
|
-
if (!jarFile) {
|
|
337
|
-
warn(t('plugin.notFound', rawName));
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
step(`${t('plugin.checkingUpdates')} ${highlight(slug)}`);
|
|
341
|
-
try {
|
|
342
|
-
const detail = await fetchPluginDetail(slug);
|
|
343
|
-
const latest = detail.releases.find(r => r.is_stable) || detail.releases[0];
|
|
344
|
-
if (!latest) {
|
|
345
|
-
warn(t('plugin.noRelease', slug));
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
const tracked = await getInstalledPlugins();
|
|
349
|
-
const meta = tracked.find(p => p.slug === slug);
|
|
350
|
-
if (meta && meta.version === latest.version) {
|
|
351
|
-
info(t('plugin.alreadyLatest', slug, latest.version));
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
const file = latest.files[0];
|
|
355
|
-
if (!file) {
|
|
356
|
-
warn(t('plugin.noFile', slug, latest.version));
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
// Backup old
|
|
360
|
-
const oldPath = join(pluginsDir, jarFile);
|
|
361
|
-
const backupPath = join(pluginsDir, `${jarFile}.old`);
|
|
362
|
-
await fsRename(oldPath, backupPath);
|
|
363
|
-
// Download new
|
|
364
|
-
const downloadUrl = proxyDownloadUrl(slug, latest.version);
|
|
365
|
-
const newPath = join(pluginsDir, file.name);
|
|
366
|
-
await downloadFile(downloadUrl, newPath, file.name);
|
|
367
|
-
// Remove backup
|
|
368
|
-
await rm(backupPath).catch(() => { });
|
|
369
|
-
// Update tracking
|
|
370
|
-
await saveInstalledPlugin({
|
|
371
|
-
slug,
|
|
372
|
-
name: detail.name,
|
|
373
|
-
version: latest.version,
|
|
374
|
-
installedAt: new Date().toISOString(),
|
|
375
|
-
fileName: file.name,
|
|
376
|
-
});
|
|
377
|
-
success(t('plugin.updateDone', detail.name, latest.version));
|
|
378
|
-
}
|
|
379
|
-
catch (err) {
|
|
380
|
-
error(t('plugin.updateError', rawName));
|
|
381
|
-
if (err.message)
|
|
382
|
-
warn(err.message);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
1
|
+
export {};
|
package/dist/commands/start.d.ts
CHANGED
package/dist/commands/start.js
CHANGED
|
@@ -1,108 +1,75 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
3
2
|
import { join } from 'node:path';
|
|
4
3
|
import { cwd } from 'node:process';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
child.on('error', () => resolve({ ok: false, version: '?' }));
|
|
25
|
-
child.stderr.on('data', (data) => {
|
|
26
|
-
output += data.toString();
|
|
27
|
-
});
|
|
28
|
-
child.on('close', () => {
|
|
29
|
-
const match = output.match(/(?:openjdk|java) version "?(?:1\.)?(\d+)/);
|
|
30
|
-
if (match) {
|
|
31
|
-
const ver = parseInt(match[1], 10);
|
|
32
|
-
resolve({ ok: ver >= 21, version: String(ver) });
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
resolve({ ok: false, version: '?' });
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
export async function startCmd(options) {
|
|
41
|
-
const serverPath = options.dir ? join(cwd(), options.dir) : ((await resolveServerDir()) || cwd());
|
|
42
|
-
if (options.dir) {
|
|
43
|
-
process.chdir(serverPath);
|
|
44
|
-
}
|
|
45
|
-
if (!existsSync(join(serverPath, 'powernukkitx.jar'))) {
|
|
46
|
-
info(t('start.jarNotFound'));
|
|
47
|
-
const createNow = await confirm({
|
|
48
|
-
message: t('start.createPrompt'),
|
|
49
|
-
default: true,
|
|
50
|
-
});
|
|
51
|
-
if (createNow) {
|
|
52
|
-
await initCmd({ dir: serverPath });
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
error(t('start.jarNotFound'));
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
header(`🚀 ${t('start.title')}`);
|
|
59
|
-
let memory = options.memory || '2G';
|
|
60
|
-
let autoRestart = options.restart ?? false;
|
|
61
|
-
if (options.interactive) {
|
|
62
|
-
memory = await input({
|
|
63
|
-
message: 'Memory allocation',
|
|
64
|
-
default: memory,
|
|
65
|
-
});
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { defineCommand } from 'citty';
|
|
6
|
+
import { intro, outro, log, spin } from '../ui/output.js';
|
|
7
|
+
import { promptConfirm } from '../ui/prompts.js';
|
|
8
|
+
import { resolveServerDir, checkJava, findJava, buildLaunchArgs, javaEnv } from '../services/server.js';
|
|
9
|
+
import { savePid } from '../services/process.js';
|
|
10
|
+
import { JAR_NAME } from '../infra/paths.js';
|
|
11
|
+
import { t } from '../i18n/index.js';
|
|
12
|
+
export async function runStart(opts) {
|
|
13
|
+
const serverPath = opts.dir
|
|
14
|
+
? (opts.dir.includes(':') || opts.dir.startsWith('/') ? opts.dir : join(cwd(), opts.dir))
|
|
15
|
+
: (await resolveServerDir()) ?? cwd();
|
|
16
|
+
if (!existsSync(join(serverPath, JAR_NAME))) {
|
|
17
|
+
log.warn(t('start.notFound'));
|
|
18
|
+
if (!(await promptConfirm(t('start.createPrompt'), true)))
|
|
19
|
+
process.exit(0);
|
|
20
|
+
const { initCmd } = await import('./init.js');
|
|
21
|
+
await initCmd.run({ args: { dir: serverPath } });
|
|
22
|
+
return;
|
|
66
23
|
}
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
24
|
+
intro(`🚀 ${t('start.title')}`);
|
|
25
|
+
const sp = spin(t('start.checkingJava'));
|
|
26
|
+
const java = await checkJava();
|
|
27
|
+
if (!java.ok) {
|
|
28
|
+
sp.fail(t('start.javaNotFound'));
|
|
71
29
|
process.exit(1);
|
|
72
30
|
}
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'-jar', 'powernukkitx.jar',
|
|
81
|
-
];
|
|
82
|
-
if (options.generateOnly) {
|
|
83
|
-
console.log(`\n ${highlight.bold(t('start.generatedCommand'))}`);
|
|
84
|
-
console.log(` ${chalk.cyan(`${java} ${cmdArgs.join(' ')}`)}\n`);
|
|
31
|
+
sp.stop(t('start.javaOk', String(java.version)));
|
|
32
|
+
const mem = opts.memory ?? '2G';
|
|
33
|
+
const cmdArgs = buildLaunchArgs(mem);
|
|
34
|
+
const javaExe = findJava();
|
|
35
|
+
if (opts.dryRun) {
|
|
36
|
+
log.info(`${javaExe} ${cmdArgs.join(' ')}`);
|
|
37
|
+
outro(t('start.generated'));
|
|
85
38
|
return;
|
|
86
39
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (code !== 0 && autoRestart) {
|
|
98
|
-
info(t('start.restarting'));
|
|
99
|
-
runServer();
|
|
40
|
+
log.step(`${t('start.starting')} (memory: ${mem})`);
|
|
41
|
+
const run = () => {
|
|
42
|
+
const child = spawn(javaExe, cmdArgs, { stdio: 'inherit', env: javaEnv(), cwd: serverPath });
|
|
43
|
+
if (child.pid)
|
|
44
|
+
savePid(child.pid, serverPath);
|
|
45
|
+
log.success(t('start.running', String(child.pid)));
|
|
46
|
+
child.on('exit', code => {
|
|
47
|
+
if (code !== 0 && opts.restart) {
|
|
48
|
+
log.warn(t('start.restarting'));
|
|
49
|
+
run();
|
|
100
50
|
}
|
|
101
|
-
else
|
|
102
|
-
|
|
51
|
+
else {
|
|
52
|
+
log.info(t('start.stopped', String(code ?? '?')));
|
|
103
53
|
process.exit(code ?? 0);
|
|
104
54
|
}
|
|
105
55
|
});
|
|
106
56
|
};
|
|
107
|
-
|
|
57
|
+
run();
|
|
108
58
|
}
|
|
59
|
+
export const startCmd = defineCommand({
|
|
60
|
+
meta: { description: 'Start the PowerNukkitX server' },
|
|
61
|
+
args: {
|
|
62
|
+
dir: { type: 'string', description: 'Server directory' },
|
|
63
|
+
memory: { type: 'string', description: 'Memory (e.g. 2G)', default: '2G' },
|
|
64
|
+
restart: { type: 'boolean', description: 'Auto-restart on crash', default: false },
|
|
65
|
+
'dry-run': { type: 'boolean', description: 'Print command without running', default: false },
|
|
66
|
+
},
|
|
67
|
+
async run({ args }) {
|
|
68
|
+
await runStart({
|
|
69
|
+
dir: args.dir,
|
|
70
|
+
memory: args.memory,
|
|
71
|
+
restart: args.restart,
|
|
72
|
+
dryRun: args['dry-run'],
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineCommand } from 'citty';
|
|
2
|
+
import { intro, outro, log, spin } from '../ui/output.js';
|
|
3
|
+
import { loadPid, clearPid, killProcess, isAlive } from '../services/process.js';
|
|
4
|
+
import { t } from '../i18n/index.js';
|
|
5
|
+
export async function runStop() {
|
|
6
|
+
intro(`⏹ ${t('stop.title')}`);
|
|
7
|
+
const pid = await loadPid();
|
|
8
|
+
if (!pid || !isAlive(pid.pid)) {
|
|
9
|
+
log.warn(t('stop.notRunning'));
|
|
10
|
+
await clearPid();
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const sp = spin(t('stop.killing', String(pid.pid)));
|
|
14
|
+
const ok = await killProcess(pid.pid);
|
|
15
|
+
await clearPid();
|
|
16
|
+
if (ok) {
|
|
17
|
+
sp.stop(t('stop.done'));
|
|
18
|
+
outro(t('stop.done'));
|
|
19
|
+
}
|
|
20
|
+
else
|
|
21
|
+
sp.fail(t('stop.failed'));
|
|
22
|
+
}
|
|
23
|
+
export const stopCmd = defineCommand({
|
|
24
|
+
meta: { description: 'Stop the running PowerNukkitX server' },
|
|
25
|
+
args: {},
|
|
26
|
+
run: () => runStop(),
|
|
27
|
+
});
|