@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.
- package/LICENSE +21 -0
- package/README.md +110 -101
- package/dist/cli.js +34 -0
- package/dist/commands/backup.d.ts +2 -1
- package/dist/commands/backup.js +23 -74
- package/dist/commands/config.d.ts +1 -1
- package/dist/commands/config.js +60 -114
- package/dist/commands/console.d.ts +2 -0
- package/dist/commands/console.js +98 -0
- package/dist/commands/doctor.d.ts +2 -1
- package/dist/commands/doctor.js +97 -119
- package/dist/commands/info.d.ts +2 -1
- package/dist/commands/info.js +41 -36
- package/dist/commands/init.d.ts +2 -4
- package/dist/commands/init.js +87 -73
- package/dist/commands/install.js +45 -0
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +60 -0
- package/dist/commands/menu.js +94 -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 +39 -0
- package/dist/commands/plugin/install.d.ts +2 -0
- package/dist/commands/plugin/install.js +56 -0
- package/dist/commands/plugin/installed.d.ts +2 -0
- package/dist/commands/plugin/installed.js +41 -0
- package/dist/commands/plugin/list.d.ts +2 -0
- package/dist/commands/plugin/list.js +47 -0
- package/dist/commands/plugin/remove.d.ts +2 -0
- package/dist/commands/plugin/remove.js +44 -0
- package/dist/commands/plugin/search.d.ts +2 -0
- package/dist/commands/plugin/search.js +11 -0
- package/dist/commands/plugin/update.d.ts +2 -0
- package/dist/commands/plugin/update.js +52 -0
- package/dist/commands/start.d.ts +2 -7
- package/dist/commands/start.js +74 -108
- package/dist/commands/stop.d.ts +2 -0
- package/dist/commands/stop.js +26 -0
- package/dist/commands/update.d.ts +2 -5
- package/dist/commands/update.js +34 -55
- package/dist/commands/use.d.ts +2 -0
- package/dist/commands/use.js +39 -0
- package/dist/infra/http.js +119 -0
- package/dist/infra/paths.js +15 -0
- package/dist/infra/store.js +24 -0
- package/dist/services/backup.js +34 -0
- package/dist/services/plugins.js +139 -0
- package/dist/services/process.js +41 -0
- package/dist/services/release.js +51 -0
- package/dist/services/server.js +81 -0
- package/dist/ui/output.js +67 -0
- package/dist/ui/prompts.js +26 -0
- package/dist/ui/theme.js +16 -0
- package/package.json +44 -63
- package/dist/bundle.js +0 -18871
- package/dist/commands/plugin.d.ts +0 -12
- package/dist/commands/plugin.js +0 -385
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -260
- package/dist/lang/en.json +0 -178
- package/dist/lang/fr.json +0 -178
- package/dist/lang/index.d.ts +0 -7
- package/dist/lang/index.js +0 -83
- package/dist/plugins.json +0 -66
- package/dist/types.d.ts +0 -61
- package/dist/types.js +0 -1
- package/dist/utils/api.d.ts +0 -18
- package/dist/utils/api.js +0 -74
- package/dist/utils/github.d.ts +0 -27
- package/dist/utils/github.js +0 -187
- package/dist/utils/logger.d.ts +0 -15
- package/dist/utils/logger.js +0 -72
- package/dist/utils/pause.d.ts +0 -1
- package/dist/utils/pause.js +0 -6
- package/dist/utils/plugins.d.ts +0 -4
- package/dist/utils/plugins.js +0 -34
- package/dist/utils/server.d.ts +0 -3
- package/dist/utils/server.js +0 -39
- package/dist/utils/updater.d.ts +0 -1
- package/dist/utils/updater.js +0 -86
package/dist/utils/api.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import https from 'node:https';
|
|
2
|
-
import http from 'node:http';
|
|
3
|
-
import { t } from '../lang/index.js';
|
|
4
|
-
let API_BASE = process.env.PNX_API_URL || 'http://localhost:3000';
|
|
5
|
-
if (API_BASE.endsWith('/'))
|
|
6
|
-
API_BASE = API_BASE.slice(0, -1);
|
|
7
|
-
function agentGet(url, redirects = 5) {
|
|
8
|
-
if (redirects <= 0)
|
|
9
|
-
return Promise.reject(new Error('Too many redirects'));
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
const mod = url.startsWith('https') ? https : http;
|
|
12
|
-
mod.get(url, { timeout: 15_000, headers: { 'User-Agent': 'pnx-cli' } }, (res) => {
|
|
13
|
-
const code = res.statusCode ?? 0;
|
|
14
|
-
if ([301, 302, 303, 307, 308].includes(code)) {
|
|
15
|
-
if (res.headers.location) {
|
|
16
|
-
resolve(agentGet(res.headers.location, redirects - 1));
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
if (code !== 200) {
|
|
21
|
-
reject(new Error(`HTTP ${code}`));
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
let data = '';
|
|
25
|
-
res.on('data', (chunk) => (data += chunk));
|
|
26
|
-
res.on('end', () => resolve(data));
|
|
27
|
-
})
|
|
28
|
-
.on('error', reject)
|
|
29
|
-
.on('timeout', function () { this?.destroy(); reject(new Error(t('errors.timeout'))); });
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
export async function fetchJSON(url) {
|
|
33
|
-
const raw = await agentGet(url);
|
|
34
|
-
return JSON.parse(raw);
|
|
35
|
-
}
|
|
36
|
-
export async function fetchPluginsList(params) {
|
|
37
|
-
const qs = new URLSearchParams();
|
|
38
|
-
if (params?.sort)
|
|
39
|
-
qs.set('sort', params.sort);
|
|
40
|
-
if (params?.limit)
|
|
41
|
-
qs.set('limit', String(params.limit));
|
|
42
|
-
if (params?.page)
|
|
43
|
-
qs.set('page', String(params.page));
|
|
44
|
-
if (params?.q)
|
|
45
|
-
qs.set('q', params.q);
|
|
46
|
-
const query = qs.toString();
|
|
47
|
-
const url = `${API_BASE}/api/plugins/cli${query ? `?${query}` : ''}`;
|
|
48
|
-
return fetchJSON(url);
|
|
49
|
-
}
|
|
50
|
-
export async function fetchPluginDetail(slug) {
|
|
51
|
-
const url = `${API_BASE}/api/plugins/cli/${encodeURIComponent(slug)}`;
|
|
52
|
-
return fetchJSON(url);
|
|
53
|
-
}
|
|
54
|
-
export async function resolveDownload(slug, version) {
|
|
55
|
-
const qs = new URLSearchParams();
|
|
56
|
-
qs.set('resolve', '1');
|
|
57
|
-
if (version)
|
|
58
|
-
qs.set('version', version);
|
|
59
|
-
const url = `${API_BASE}/api/plugins/${encodeURIComponent(slug)}/download?${qs.toString()}`;
|
|
60
|
-
const data = await fetchJSON(url);
|
|
61
|
-
return {
|
|
62
|
-
url: data.url || data.download_url,
|
|
63
|
-
name: data.name || data.file_name || `${slug}.jar`,
|
|
64
|
-
size: data.size || 0,
|
|
65
|
-
version: data.version || version || 'latest',
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
export function proxyDownloadUrl(slug, version) {
|
|
69
|
-
const qs = new URLSearchParams();
|
|
70
|
-
qs.set('proxy', '1');
|
|
71
|
-
if (version)
|
|
72
|
-
qs.set('version', version);
|
|
73
|
-
return `${API_BASE}/api/plugins/${encodeURIComponent(slug)}/download?${qs.toString()}`;
|
|
74
|
-
}
|
package/dist/utils/github.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
interface GitHubAsset {
|
|
2
|
-
name: string;
|
|
3
|
-
browser_download_url: string;
|
|
4
|
-
size: number;
|
|
5
|
-
}
|
|
6
|
-
interface GitHubRelease {
|
|
7
|
-
tag_name: string;
|
|
8
|
-
assets: GitHubAsset[];
|
|
9
|
-
published_at: string;
|
|
10
|
-
body: string;
|
|
11
|
-
}
|
|
12
|
-
export declare function fetchJSON(url: string, redirects?: number): Promise<any>;
|
|
13
|
-
export declare function getLatestRelease(): Promise<GitHubRelease>;
|
|
14
|
-
export declare function findAsset(release: GitHubRelease, name: string): Promise<GitHubAsset | undefined>;
|
|
15
|
-
export declare function findPluginAsset(repo: string, assetName: string): Promise<{
|
|
16
|
-
url: string;
|
|
17
|
-
size: number;
|
|
18
|
-
} | null>;
|
|
19
|
-
export declare function downloadFile(url: string, dest: string, label?: string): Promise<void>;
|
|
20
|
-
export declare function generateServerId(): string;
|
|
21
|
-
export declare function getDefaultJavaArgs(): string[];
|
|
22
|
-
export declare function getJavaEnv(): Record<string, string>;
|
|
23
|
-
export declare function getStartScripts(): {
|
|
24
|
-
url: string;
|
|
25
|
-
name: string;
|
|
26
|
-
}[];
|
|
27
|
-
export {};
|
package/dist/utils/github.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import https from 'node:https';
|
|
2
|
-
import http from 'node:http';
|
|
3
|
-
import { randomBytes } from 'node:crypto';
|
|
4
|
-
import { createWriteStream, existsSync } from 'node:fs';
|
|
5
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
6
|
-
import { homedir, platform } from 'node:os';
|
|
7
|
-
import { join } from 'node:path';
|
|
8
|
-
import chalk from 'chalk';
|
|
9
|
-
import { step } from './logger.js';
|
|
10
|
-
import { t } from '../lang/index.js';
|
|
11
|
-
const CACHE_DIR = join(homedir(), '.pnx-cli');
|
|
12
|
-
const CACHE_FILE = join(CACHE_DIR, 'latest-release.json');
|
|
13
|
-
const CACHE_TTL = 3_600_000;
|
|
14
|
-
export async function fetchJSON(url, redirects = 5) {
|
|
15
|
-
if (redirects <= 0)
|
|
16
|
-
return Promise.reject(new Error('Too many redirects'));
|
|
17
|
-
return new Promise((resolve, reject) => {
|
|
18
|
-
const mod = url.startsWith('https') ? https : http;
|
|
19
|
-
mod.get(url, { timeout: 15_000, headers: { 'User-Agent': 'pnx-cli' } }, (res) => {
|
|
20
|
-
const code = res.statusCode ?? 0;
|
|
21
|
-
if ([301, 302, 303, 307, 308].includes(code)) {
|
|
22
|
-
if (res.headers.location) {
|
|
23
|
-
resolve(fetchJSON(res.headers.location, redirects - 1));
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
if (code !== 200) {
|
|
28
|
-
reject(new Error(`HTTP ${code}`));
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
let data = '';
|
|
32
|
-
res.on('data', (chunk) => (data += chunk));
|
|
33
|
-
res.on('end', () => {
|
|
34
|
-
try {
|
|
35
|
-
resolve(JSON.parse(data));
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
reject(new Error('Invalid JSON response'));
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
})
|
|
42
|
-
.on('error', reject)
|
|
43
|
-
.on('timeout', function () {
|
|
44
|
-
this?.destroy();
|
|
45
|
-
reject(new Error(t('errors.timeout')));
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
async function getCachedRelease() {
|
|
50
|
-
try {
|
|
51
|
-
if (existsSync(CACHE_FILE)) {
|
|
52
|
-
const raw = await readFile(CACHE_FILE, 'utf-8');
|
|
53
|
-
const cached = JSON.parse(raw);
|
|
54
|
-
if (Date.now() - cached.fetchedAt < CACHE_TTL) {
|
|
55
|
-
return cached.data;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch { /* ignore */ }
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
async function setCachedRelease(data) {
|
|
63
|
-
try {
|
|
64
|
-
await mkdir(CACHE_DIR, { recursive: true });
|
|
65
|
-
await writeFile(CACHE_FILE, JSON.stringify({ fetchedAt: Date.now(), data }), 'utf-8');
|
|
66
|
-
}
|
|
67
|
-
catch { /* ignore */ }
|
|
68
|
-
}
|
|
69
|
-
export async function getLatestRelease() {
|
|
70
|
-
const cached = await getCachedRelease();
|
|
71
|
-
if (cached)
|
|
72
|
-
return cached;
|
|
73
|
-
const data = await fetchJSON('https://api.github.com/repos/PowerNukkitX/PowerNukkitX/releases/latest');
|
|
74
|
-
await setCachedRelease(data);
|
|
75
|
-
return data;
|
|
76
|
-
}
|
|
77
|
-
export async function findAsset(release, name) {
|
|
78
|
-
return release.assets.find((a) => a.name === name);
|
|
79
|
-
}
|
|
80
|
-
export async function findPluginAsset(repo, assetName) {
|
|
81
|
-
try {
|
|
82
|
-
const data = await fetchJSON(`https://api.github.com/repos/${repo}/releases/latest`);
|
|
83
|
-
const asset = data.assets.find((a) => a.name === assetName);
|
|
84
|
-
if (asset)
|
|
85
|
-
return { url: asset.browser_download_url, size: asset.size };
|
|
86
|
-
}
|
|
87
|
-
catch { /* not found */ }
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
export function downloadFile(url, dest, label) {
|
|
91
|
-
const fileName = label || dest.split(/[/\\]/).pop() || 'file';
|
|
92
|
-
step(chalk.cyan(fileName));
|
|
93
|
-
function doGet(targetUrl, redirects = 5) {
|
|
94
|
-
if (redirects <= 0)
|
|
95
|
-
return Promise.reject(new Error('Too many redirects'));
|
|
96
|
-
return new Promise((resolve, reject) => {
|
|
97
|
-
const file = createWriteStream(dest);
|
|
98
|
-
const mod = targetUrl.startsWith('https') ? https : http;
|
|
99
|
-
mod.get(targetUrl, { timeout: 120_000, headers: { 'User-Agent': 'pnx-cli' } }, (res) => {
|
|
100
|
-
const code = res.statusCode ?? 0;
|
|
101
|
-
if ([301, 302, 303, 307, 308].includes(code)) {
|
|
102
|
-
if (res.headers.location) {
|
|
103
|
-
file.close();
|
|
104
|
-
resolve(doGet(res.headers.location, redirects - 1));
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (code !== 200) {
|
|
109
|
-
file.close();
|
|
110
|
-
reject(new Error(`HTTP ${code}`));
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
const total = parseInt(res.headers['content-length'] || '0', 10);
|
|
114
|
-
let downloaded = 0;
|
|
115
|
-
let lastPercent = -1;
|
|
116
|
-
res.on('data', (chunk) => {
|
|
117
|
-
downloaded += chunk.length;
|
|
118
|
-
if (total > 0) {
|
|
119
|
-
const percent = Math.round((downloaded / total) * 100);
|
|
120
|
-
if (percent !== lastPercent && percent % 5 === 0) {
|
|
121
|
-
const done = '━'.repeat(Math.floor(percent / 5));
|
|
122
|
-
const left = '─'.repeat(20 - Math.floor(percent / 5));
|
|
123
|
-
process.stdout.write(`\r ${chalk.hex('#4ECDC4')(done)}${chalk.dim(left)} ${chalk.bold(String(percent))}%`);
|
|
124
|
-
lastPercent = percent;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
res.pipe(file);
|
|
129
|
-
file.on('finish', () => {
|
|
130
|
-
if (total > 0)
|
|
131
|
-
process.stdout.write('\n');
|
|
132
|
-
file.close();
|
|
133
|
-
resolve();
|
|
134
|
-
});
|
|
135
|
-
})
|
|
136
|
-
.on('error', (err) => {
|
|
137
|
-
file.close();
|
|
138
|
-
reject(err);
|
|
139
|
-
})
|
|
140
|
-
.on('timeout', function () {
|
|
141
|
-
this?.destroy();
|
|
142
|
-
file.close();
|
|
143
|
-
reject(new Error(t('errors.timeout')));
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
return doGet(url);
|
|
148
|
-
}
|
|
149
|
-
export function generateServerId() {
|
|
150
|
-
return randomBytes(4).toString('hex');
|
|
151
|
-
}
|
|
152
|
-
export function getDefaultJavaArgs() {
|
|
153
|
-
return [
|
|
154
|
-
'-Dfile.encoding=UTF-8',
|
|
155
|
-
'-Dstdout.encoding=UTF-8',
|
|
156
|
-
'-Dstderr.encoding=UTF-8',
|
|
157
|
-
'-Djansi.passthrough=true',
|
|
158
|
-
'-Dterminal.ansi=true',
|
|
159
|
-
'-XX:+UseZGC',
|
|
160
|
-
'-XX:+ZGenerational',
|
|
161
|
-
'-XX:+UseStringDeduplication',
|
|
162
|
-
'--add-opens', 'java.base/java.lang=ALL-UNNAMED',
|
|
163
|
-
'--add-opens', 'java.base/java.io=ALL-UNNAMED',
|
|
164
|
-
'--add-opens', 'java.base/java.net=ALL-UNNAMED',
|
|
165
|
-
];
|
|
166
|
-
}
|
|
167
|
-
export function getJavaEnv() {
|
|
168
|
-
return {
|
|
169
|
-
...process.env,
|
|
170
|
-
JAVA_TOOL_OPTIONS: '-Dfile.encoding=UTF-8',
|
|
171
|
-
LANG: process.env.LANG || 'en_US.UTF-8',
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
const RAW_BASE = 'https://raw.githubusercontent.com/PowerNukkitX/scripts/master';
|
|
175
|
-
export function getStartScripts() {
|
|
176
|
-
const os = platform();
|
|
177
|
-
if (os === 'win32') {
|
|
178
|
-
return [
|
|
179
|
-
{ url: `${RAW_BASE}/start.bat`, name: 'start.bat' },
|
|
180
|
-
{ url: `${RAW_BASE}/start.ps1`, name: 'start.ps1' },
|
|
181
|
-
];
|
|
182
|
-
}
|
|
183
|
-
// linux, darwin, etc.
|
|
184
|
-
return [
|
|
185
|
-
{ url: `${RAW_BASE}/start.sh`, name: 'start.sh' },
|
|
186
|
-
];
|
|
187
|
-
}
|
package/dist/utils/logger.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare const logo: string;
|
|
2
|
-
export declare function success(msg: string): void;
|
|
3
|
-
export declare function error(msg: string): void;
|
|
4
|
-
export declare function warn(msg: string): void;
|
|
5
|
-
export declare function info(msg: string): void;
|
|
6
|
-
export declare function step(msg: string): void;
|
|
7
|
-
export declare function header(title: string): void;
|
|
8
|
-
export declare function subheader(title: string): void;
|
|
9
|
-
export declare function table(rows: [string, string][]): void;
|
|
10
|
-
export declare function bullet(items: string[]): void;
|
|
11
|
-
export declare function divider(): void;
|
|
12
|
-
export declare const highlight: import("chalk").ChalkInstance;
|
|
13
|
-
export declare const dim: import("chalk").ChalkInstance;
|
|
14
|
-
export declare const bold: import("chalk").ChalkInstance;
|
|
15
|
-
export declare const code: (s: string) => string;
|
package/dist/utils/logger.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
// ─── palette ──────────────────────────────────────────────────
|
|
3
|
-
const c = {
|
|
4
|
-
primary: chalk.hex('#FF6B35'),
|
|
5
|
-
accent: chalk.hex('#FF8C42'),
|
|
6
|
-
gold: chalk.hex('#FFB347'),
|
|
7
|
-
blue: chalk.hex('#6C8EBF'),
|
|
8
|
-
cyan: chalk.hex('#4ECDC4'),
|
|
9
|
-
green: chalk.hex('#4CAF50'),
|
|
10
|
-
red: chalk.hex('#E53935'),
|
|
11
|
-
yellow: chalk.hex('#FFC107'),
|
|
12
|
-
dim: chalk.dim,
|
|
13
|
-
bold: chalk.bold,
|
|
14
|
-
};
|
|
15
|
-
// ─── logo ─────────────────────────────────────────────────────
|
|
16
|
-
export const logo = `
|
|
17
|
-
${c.primary.bold(' ╭──────────────────────────────────────╮')}
|
|
18
|
-
${c.primary.bold(' │')} ${c.accent.bold('██████╗ ███╗ ██╗██╗ ██╗')} ${c.primary.bold('│')}
|
|
19
|
-
${c.primary.bold(' │')} ${c.accent.bold('██╔══██╗████╗ ██║╚██╗██╔╝')} ${c.primary.bold('│')}
|
|
20
|
-
${c.primary.bold(' │')} ${c.accent.bold('██████╔╝██╔██╗ ██║ ╚███╔╝')} ${c.primary.bold('│')}
|
|
21
|
-
${c.primary.bold(' │')} ${c.accent.bold('██╔═══╝ ██║╚██╗██║ ██╔██╗')} ${c.primary.bold('│')}
|
|
22
|
-
${c.primary.bold(' │')} ${c.accent.bold('██║ ██║ ╚████║██╔╝ ██╗')} ${c.primary.bold('│')}
|
|
23
|
-
${c.primary.bold(' │')} ${c.accent.bold('╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝')} ${c.primary.bold('│')}
|
|
24
|
-
${c.primary.bold(' ╰──────────────────────────────────────╯')}
|
|
25
|
-
${c.gold(' PowerNukkitX · Minecraft Bedrock')}
|
|
26
|
-
${c.dim(' Server Management CLI')}
|
|
27
|
-
`;
|
|
28
|
-
// ─── helpers ──────────────────────────────────────────────────
|
|
29
|
-
const pad = (s) => ` ${s}`;
|
|
30
|
-
export function success(msg) {
|
|
31
|
-
console.log(pad(`${c.green('✔')} ${c.bold(msg)}`));
|
|
32
|
-
}
|
|
33
|
-
export function error(msg) {
|
|
34
|
-
console.log(pad(`${c.red('✘')} ${c.bold(msg)}`));
|
|
35
|
-
}
|
|
36
|
-
export function warn(msg) {
|
|
37
|
-
console.log(pad(`${c.yellow('⚠')} ${msg}`));
|
|
38
|
-
}
|
|
39
|
-
export function info(msg) {
|
|
40
|
-
console.log(pad(`${c.blue('ℹ')} ${msg}`));
|
|
41
|
-
}
|
|
42
|
-
export function step(msg) {
|
|
43
|
-
console.log(pad(`${c.dim('▸')} ${c.dim(msg)}`));
|
|
44
|
-
}
|
|
45
|
-
export function header(title) {
|
|
46
|
-
const line = c.primary('─'.repeat(50));
|
|
47
|
-
console.log(`\n ${line}`);
|
|
48
|
-
console.log(` ${c.accent.bold(title)}`);
|
|
49
|
-
console.log(` ${line}`);
|
|
50
|
-
}
|
|
51
|
-
export function subheader(title) {
|
|
52
|
-
console.log(`\n ${c.accent('┃')} ${c.bold(title)}`);
|
|
53
|
-
console.log(` ${c.accent('┃')} ${c.dim('─'.repeat(Math.min(title.length, 40)))}`);
|
|
54
|
-
}
|
|
55
|
-
export function table(rows) {
|
|
56
|
-
const max = Math.max(...rows.map(([l]) => l.length));
|
|
57
|
-
for (const [label, value] of rows) {
|
|
58
|
-
console.log(pad(`${c.accent(label.padEnd(max + 2))}${value}`));
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
export function bullet(items) {
|
|
62
|
-
for (const item of items) {
|
|
63
|
-
console.log(pad(`${c.cyan('●')} ${item}`));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
export function divider() {
|
|
67
|
-
console.log(pad(c.dim('─'.repeat(50))));
|
|
68
|
-
}
|
|
69
|
-
export const highlight = c.gold;
|
|
70
|
-
export const dim = c.dim;
|
|
71
|
-
export const bold = c.bold;
|
|
72
|
-
export const code = (s) => c.cyan(s);
|
package/dist/utils/pause.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function pauseForExit(): Promise<void>;
|
package/dist/utils/pause.js
DELETED
package/dist/utils/plugins.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { InstalledPlugin } from '../types.js';
|
|
2
|
-
export declare function getInstalledPlugins(): Promise<InstalledPlugin[]>;
|
|
3
|
-
export declare function saveInstalledPlugin(plugin: InstalledPlugin): Promise<void>;
|
|
4
|
-
export declare function getPluginVersion(slug: string): Promise<string | null>;
|
package/dist/utils/plugins.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
const CACHE_DIR = join(homedir(), '.pnx-cli');
|
|
6
|
-
const PLUGINS_FILE = join(CACHE_DIR, 'installed-plugins.json');
|
|
7
|
-
export async function getInstalledPlugins() {
|
|
8
|
-
try {
|
|
9
|
-
if (!existsSync(PLUGINS_FILE))
|
|
10
|
-
return [];
|
|
11
|
-
const raw = await readFile(PLUGINS_FILE, 'utf-8');
|
|
12
|
-
return JSON.parse(raw);
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
return [];
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
export async function saveInstalledPlugin(plugin) {
|
|
19
|
-
await mkdir(CACHE_DIR, { recursive: true });
|
|
20
|
-
const list = await getInstalledPlugins();
|
|
21
|
-
const idx = list.findIndex(p => p.slug === plugin.slug);
|
|
22
|
-
if (idx >= 0) {
|
|
23
|
-
list[idx] = plugin;
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
list.push(plugin);
|
|
27
|
-
}
|
|
28
|
-
await writeFile(PLUGINS_FILE, JSON.stringify(list, null, 2), 'utf-8');
|
|
29
|
-
}
|
|
30
|
-
export async function getPluginVersion(slug) {
|
|
31
|
-
const list = await getInstalledPlugins();
|
|
32
|
-
const p = list.find(x => x.slug === slug);
|
|
33
|
-
return p ? p.version : null;
|
|
34
|
-
}
|
package/dist/utils/server.d.ts
DELETED
package/dist/utils/server.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { join, dirname, resolve } from 'node:path';
|
|
3
|
-
import { cwd } from 'node:process';
|
|
4
|
-
import { select } from '@inquirer/prompts';
|
|
5
|
-
import { highlight } from './logger.js';
|
|
6
|
-
export function detectServer(startPath) {
|
|
7
|
-
const all = detectAllServers(startPath);
|
|
8
|
-
return all[0] || null;
|
|
9
|
-
}
|
|
10
|
-
export function detectAllServers(startPath) {
|
|
11
|
-
const found = [];
|
|
12
|
-
const checkPaths = [
|
|
13
|
-
startPath || cwd(),
|
|
14
|
-
join(startPath || cwd(), 'pnx-server'),
|
|
15
|
-
startPath ? dirname(resolve(startPath)) : dirname(cwd()),
|
|
16
|
-
];
|
|
17
|
-
for (const dir of checkPaths) {
|
|
18
|
-
if (existsSync(join(dir, 'powernukkitx.jar')) && !found.includes(dir)) {
|
|
19
|
-
found.push(dir);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return found;
|
|
23
|
-
}
|
|
24
|
-
export async function resolveServerDir(label) {
|
|
25
|
-
const servers = detectAllServers();
|
|
26
|
-
if (servers.length === 0)
|
|
27
|
-
return null;
|
|
28
|
-
if (servers.length === 1)
|
|
29
|
-
return servers[0];
|
|
30
|
-
const choice = await select({
|
|
31
|
-
message: label || 'Multiple servers found. Which one to manage?',
|
|
32
|
-
pageSize: 10,
|
|
33
|
-
choices: servers.map((s) => ({
|
|
34
|
-
name: highlight(s),
|
|
35
|
-
value: s,
|
|
36
|
-
})),
|
|
37
|
-
});
|
|
38
|
-
return choice;
|
|
39
|
-
}
|
package/dist/utils/updater.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function checkForUpdates(force?: boolean): Promise<void>;
|
package/dist/utils/updater.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
import { warn, dim } from './logger.js';
|
|
7
|
-
import { getLatestRelease, findAsset } from './github.js';
|
|
8
|
-
import { fetchPluginDetail } from './api.js';
|
|
9
|
-
import { getInstalledPlugins } from './plugins.js';
|
|
10
|
-
import { detectServer } from './server.js';
|
|
11
|
-
import { t } from '../lang/index.js';
|
|
12
|
-
const CACHE_DIR = join(homedir(), '.pnx-cli');
|
|
13
|
-
const CHECK_FILE = join(CACHE_DIR, 'last-update-check.json');
|
|
14
|
-
const CHECK_TTL = 3_600_000; // 1h
|
|
15
|
-
async function getLastCheck() {
|
|
16
|
-
try {
|
|
17
|
-
if (existsSync(CHECK_FILE)) {
|
|
18
|
-
const raw = await readFile(CHECK_FILE, 'utf-8');
|
|
19
|
-
return JSON.parse(raw);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
catch { /* ignore */ }
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
async function saveCheck(data) {
|
|
26
|
-
try {
|
|
27
|
-
await mkdir(CACHE_DIR, { recursive: true });
|
|
28
|
-
await writeFile(CHECK_FILE, JSON.stringify(data), 'utf-8');
|
|
29
|
-
}
|
|
30
|
-
catch { /* ignore */ }
|
|
31
|
-
}
|
|
32
|
-
let notifsShown = false;
|
|
33
|
-
export async function checkForUpdates(force) {
|
|
34
|
-
if (notifsShown && !force)
|
|
35
|
-
return;
|
|
36
|
-
const last = await getLastCheck();
|
|
37
|
-
if (last && !force && Date.now() - last.timestamp < CHECK_TTL) {
|
|
38
|
-
notifsShown = true;
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const notifications = [];
|
|
42
|
-
// Check core update
|
|
43
|
-
try {
|
|
44
|
-
const serverPath = detectServer();
|
|
45
|
-
if (serverPath && existsSync(join(serverPath, 'powernukkitx.jar'))) {
|
|
46
|
-
const release = await getLatestRelease();
|
|
47
|
-
const tag = release.tag_name.replace(/^v/, '');
|
|
48
|
-
const asset = await findAsset(release, 'powernukkitx.jar');
|
|
49
|
-
if (asset) {
|
|
50
|
-
// Read current version from jar name or release cache
|
|
51
|
-
const cachedVersion = last?.coreVersion;
|
|
52
|
-
if (cachedVersion && cachedVersion !== tag) {
|
|
53
|
-
notifications.push(`${chalk.yellow('⟳')} ${t('updater.coreUpdate')} ${chalk.bold('v' + tag)} ${dim('(current: v' + cachedVersion + ')')} ${chalk.cyan('pnx update')}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
await saveCheck({ timestamp: Date.now(), coreVersion: tag });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch { /* silent */ }
|
|
60
|
-
// Check plugin updates
|
|
61
|
-
try {
|
|
62
|
-
const serverPath = detectServer();
|
|
63
|
-
const pluginsDir = serverPath ? join(serverPath, 'plugins') : join(process.cwd(), 'plugins');
|
|
64
|
-
if (existsSync(pluginsDir)) {
|
|
65
|
-
const installed = await getInstalledPlugins();
|
|
66
|
-
for (const p of installed) {
|
|
67
|
-
try {
|
|
68
|
-
const detail = await fetchPluginDetail(p.slug);
|
|
69
|
-
if (detail.latest_version !== p.version) {
|
|
70
|
-
notifications.push(`${chalk.yellow('⟳')} ${t('updater.pluginUpdate', detail.name, chalk.bold('v' + detail.latest_version), dim('(current: v' + p.version + ')'))} ${chalk.cyan(`pnx plugin update ${p.slug}`)}`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch { /* skip if plugin not found on marketplace */ }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
catch { /* silent */ }
|
|
78
|
-
if (notifications.length > 0) {
|
|
79
|
-
console.log();
|
|
80
|
-
for (const n of notifications) {
|
|
81
|
-
warn(n);
|
|
82
|
-
}
|
|
83
|
-
console.log();
|
|
84
|
-
}
|
|
85
|
-
notifsShown = true;
|
|
86
|
-
}
|