@powernukkitx/cli 0.0.2 → 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.
Files changed (82) hide show
  1. package/README.md +203 -177
  2. package/dist/bundle.js +3 -18856
  3. package/dist/cli.js +46 -0
  4. package/dist/commands/backup.d.ts +2 -1
  5. package/dist/commands/backup.js +21 -71
  6. package/dist/commands/cfg.d.ts +2 -0
  7. package/dist/commands/cfg.js +61 -0
  8. package/dist/commands/config.js +52 -105
  9. package/dist/commands/console.d.ts +2 -0
  10. package/dist/commands/console.js +99 -0
  11. package/dist/commands/doctor.d.ts +2 -1
  12. package/dist/commands/doctor.js +87 -108
  13. package/dist/commands/info.d.ts +2 -1
  14. package/dist/commands/info.js +39 -33
  15. package/dist/commands/init.d.ts +2 -4
  16. package/dist/commands/init.js +58 -65
  17. package/dist/commands/lang.d.ts +2 -0
  18. package/dist/commands/lang.js +28 -0
  19. package/dist/commands/logs.d.ts +2 -0
  20. package/dist/commands/logs.js +61 -0
  21. package/dist/commands/menu.js +86 -0
  22. package/dist/commands/plugin/index.d.ts +2 -0
  23. package/dist/commands/plugin/index.js +13 -0
  24. package/dist/commands/plugin/info.d.ts +2 -0
  25. package/dist/commands/plugin/info.js +40 -0
  26. package/dist/commands/plugin/install.d.ts +2 -0
  27. package/dist/commands/plugin/install.js +57 -0
  28. package/dist/commands/plugin/installed.d.ts +2 -0
  29. package/dist/commands/plugin/installed.js +42 -0
  30. package/dist/commands/plugin/list.d.ts +2 -0
  31. package/dist/commands/plugin/list.js +49 -0
  32. package/dist/commands/plugin/remove.d.ts +2 -0
  33. package/dist/commands/plugin/remove.js +45 -0
  34. package/dist/commands/plugin/search.d.ts +2 -0
  35. package/dist/commands/plugin/search.js +12 -0
  36. package/dist/commands/plugin/update.d.ts +2 -0
  37. package/dist/commands/plugin/update.js +53 -0
  38. package/dist/commands/plugin.d.ts +1 -12
  39. package/dist/commands/plugin.js +1 -385
  40. package/dist/commands/start.d.ts +2 -7
  41. package/dist/commands/start.js +61 -94
  42. package/dist/commands/stop.d.ts +2 -0
  43. package/dist/commands/stop.js +27 -0
  44. package/dist/commands/update.d.ts +2 -5
  45. package/dist/commands/update.js +30 -50
  46. package/dist/commands/use.d.ts +2 -0
  47. package/dist/commands/use.js +40 -0
  48. package/dist/core/config.d.ts +13 -0
  49. package/dist/core/config.js +31 -0
  50. package/dist/core/network.d.ts +13 -0
  51. package/dist/core/network.js +139 -0
  52. package/dist/core/output.d.ts +33 -0
  53. package/dist/core/output.js +75 -0
  54. package/dist/core/process.d.ts +10 -0
  55. package/dist/core/process.js +53 -0
  56. package/dist/i18n/en.json +174 -0
  57. package/dist/i18n/fr.json +174 -0
  58. package/dist/i18n/index.js +58 -0
  59. package/dist/index.d.ts +0 -1
  60. package/dist/index.js +1 -260
  61. package/dist/infra/http.js +121 -0
  62. package/dist/infra/paths.js +20 -0
  63. package/dist/infra/store.js +27 -0
  64. package/dist/lang/en.json +116 -148
  65. package/dist/lang/fr.json +115 -147
  66. package/dist/main.d.ts +2 -0
  67. package/dist/main.js +28 -0
  68. package/dist/services/backup.js +40 -0
  69. package/dist/services/plugins.js +111 -0
  70. package/dist/services/process.js +43 -0
  71. package/dist/services/release.js +38 -0
  72. package/dist/services/server.js +89 -0
  73. package/dist/ui/output.js +71 -0
  74. package/dist/ui/prompts.js +30 -0
  75. package/dist/ui/theme.js +18 -0
  76. package/dist/utils/api.d.ts +3 -12
  77. package/dist/utils/api.js +7 -57
  78. package/dist/utils/github.d.ts +3 -10
  79. package/dist/utils/github.js +27 -154
  80. package/dist/utils/server.d.ts +2 -2
  81. package/dist/utils/server.js +17 -24
  82. package/package.json +15 -32
@@ -0,0 +1,40 @@
1
+ import { defineCommand } from 'citty';
2
+ import { intro, outro, log, spin } from '../../ui/output.js';
3
+ import { c } from '../../ui/theme.js';
4
+ import { promptText } from '../../ui/prompts.js';
5
+ import { getPluginDetail } from '../../services/plugins.js';
6
+ import { t } from '../../i18n/index.js';
7
+ export const infoCmd = defineCommand({
8
+ meta: { description: 'Show plugin details' },
9
+ args: { slug: { type: 'positional', description: 'Plugin slug', required: false } },
10
+ async run({ args }) {
11
+ const slug = args.slug ?? await promptText({ message: t('plugin.slugPrompt') });
12
+ const sp = spin(slug);
13
+ try {
14
+ const d = await getPluginDetail(slug);
15
+ sp.stop(d.name);
16
+ intro(`📖 ${d.name}`);
17
+ if (d.description)
18
+ log.dim(d.description);
19
+ log.info(`Author: ${c.accent(d.author)}`);
20
+ log.info(`Version: ${c.green(d.latest_version)}`);
21
+ log.info(`Downloads: ${c.cyan(d.downloads >= 1000 ? (d.downloads / 1000).toFixed(1) + 'k' : String(d.downloads))}`);
22
+ log.info(`Updated: ${new Date(d.updated_at).toLocaleDateString()}`);
23
+ if (d.tags.length)
24
+ log.info(`Tags: ${d.tags.map(tag => c.cyan(tag)).join(', ')}`);
25
+ if (d.repository_url)
26
+ log.info(`Repo: ${c.blue(d.repository_url)}`);
27
+ if (d.releases.length) {
28
+ log.step(t('plugin.versionsAvailable'));
29
+ for (const r of d.releases.slice(0, 5)) {
30
+ const stable = r.is_stable ? c.green('●') : c.dim('○');
31
+ log.raw(` ${stable} v${r.version} ${c.dim(new Date(r.created_at).toLocaleDateString())}`);
32
+ }
33
+ }
34
+ outro('');
35
+ }
36
+ catch {
37
+ sp.fail(t('plugin.notFound', slug));
38
+ }
39
+ },
40
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandDef } from 'citty';
2
+ export declare const installCmd: CommandDef;
@@ -0,0 +1,57 @@
1
+ import { join } from 'node:path';
2
+ import { defineCommand } from 'citty';
3
+ import { intro, outro, log, spin, progress } from '../../ui/output.js';
4
+ import { promptMulti } from '../../ui/prompts.js';
5
+ import { resolveServerDir } from '../../services/server.js';
6
+ import { searchPlugins, installPlugin, installFromUrl } from '../../services/plugins.js';
7
+ import { t } from '../../i18n/index.js';
8
+ export const installCmd = defineCommand({
9
+ meta: { description: 'Install plugins' },
10
+ args: { names: { type: 'positional', description: 'Plugin slugs or .jar URLs', required: false } },
11
+ async run({ args }) {
12
+ const serverPath = (await resolveServerDir()) ?? '.';
13
+ const pluginsDir = join(serverPath, 'plugins');
14
+ let names = args.names ? [args.names] : [];
15
+ if (names.length === 0) {
16
+ intro(`📦 ${t('plugin.titleInstall')}`);
17
+ const sp = spin(t('plugin.fetching'));
18
+ const resp = await searchPlugins({ sort: 'stars', limit: 50 });
19
+ sp.stop(`${resp.plugins.length} plugins`);
20
+ names = await promptMulti(t('plugin.selectInstall'), resp.plugins.map(p => ({ value: p.slug, label: p.name, hint: p.description })));
21
+ if (names.length === 0) {
22
+ log.info(t('plugin.noneSelected'));
23
+ return;
24
+ }
25
+ }
26
+ intro(`📦 ${t('plugin.titleInstall')}`);
27
+ for (const name of names) {
28
+ if (name.startsWith('http://') || name.startsWith('https://')) {
29
+ try {
30
+ const file = await installFromUrl(name, pluginsDir, (pct, f) => progress(pct, f));
31
+ log.success(t('plugin.installSuccess', file));
32
+ }
33
+ catch {
34
+ log.error(t('plugin.urlInvalid'));
35
+ }
36
+ continue;
37
+ }
38
+ const sp = spin(name);
39
+ try {
40
+ const entry = await installPlugin(name, pluginsDir, (pct, f) => progress(pct, f));
41
+ sp.stop(`${entry.name} v${entry.version}`);
42
+ log.success(t('plugin.installSuccess', entry.name));
43
+ }
44
+ catch (e) {
45
+ const msg = e.message;
46
+ if (msg.startsWith('no-release'))
47
+ sp.fail(t('plugin.noRelease', name));
48
+ else if (msg.startsWith('no-file'))
49
+ sp.fail(t('plugin.noFile', name));
50
+ else
51
+ sp.fail(t('plugin.installError', name));
52
+ }
53
+ }
54
+ log.info(t('plugin.restartHint'));
55
+ outro('');
56
+ },
57
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandDef } from 'citty';
2
+ export declare const installedCmd: CommandDef;
@@ -0,0 +1,42 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { defineCommand } from 'citty';
5
+ import { intro, outro, log, isJson, json } from '../../ui/output.js';
6
+ import { c } from '../../ui/theme.js';
7
+ import { resolveServerDir } from '../../services/server.js';
8
+ import { getInstalled } from '../../services/plugins.js';
9
+ import { t } from '../../i18n/index.js';
10
+ export const installedCmd = defineCommand({
11
+ meta: { description: 'List installed plugins' },
12
+ args: {},
13
+ async run() {
14
+ const serverPath = await resolveServerDir();
15
+ const pluginsDir = serverPath ? join(serverPath, 'plugins') : 'plugins';
16
+ if (!existsSync(pluginsDir)) {
17
+ if (isJson())
18
+ json({ plugins: [] });
19
+ log.warn(t('plugin.noPluginsDir'));
20
+ return;
21
+ }
22
+ const jars = (await readdir(pluginsDir)).filter(f => f.endsWith('.jar'));
23
+ if (isJson())
24
+ json({ plugins: jars.map(j => ({ file: j })) });
25
+ intro(`📁 ${t('plugin.titleInstalled')}`);
26
+ if (jars.length === 0) {
27
+ log.warn(t('plugin.noPlugins'));
28
+ return;
29
+ }
30
+ const tracked = await getInstalled();
31
+ for (const j of jars) {
32
+ const meta = tracked.find(p => p.fileName === j);
33
+ if (meta)
34
+ log.raw(` ${c.accent('●')} ${c.bold(meta.name)} ${c.dim('v' + meta.version)}`);
35
+ else
36
+ log.raw(` ${c.dim('○')} ${j.replace('.jar', '')}`);
37
+ }
38
+ log.info(t('plugin.count', String(jars.length)));
39
+ log.info(t('plugin.restartHint'));
40
+ outro('');
41
+ },
42
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandDef } from 'citty';
2
+ export declare const listCmd: CommandDef;
@@ -0,0 +1,49 @@
1
+ import { defineCommand } from 'citty';
2
+ import { intro, outro, log, spin, isJson, json } from '../../ui/output.js';
3
+ import { c } from '../../ui/theme.js';
4
+ import { searchPlugins } from '../../services/plugins.js';
5
+ import { t } from '../../i18n/index.js';
6
+ function stars(n) {
7
+ const full = '★'.repeat(Math.min(Math.floor(n / 10), 5));
8
+ const empty = '☆'.repeat(5 - full.length);
9
+ return (n >= 50 ? c.yellow : c.dim)(full + empty);
10
+ }
11
+ function dl(n) { return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n); }
12
+ /** Rendu partagé (utilisé par `list` et `search`). */
13
+ export async function renderList(params) {
14
+ const sp = spin(t('plugin.fetching'));
15
+ try {
16
+ const resp = await searchPlugins(params);
17
+ sp.stop(`${resp.plugins.length} plugins`);
18
+ if (isJson())
19
+ json({ plugins: resp.plugins, count: resp.count });
20
+ intro(`📋 ${t('plugin.titleList')}`);
21
+ for (const p of resp.plugins) {
22
+ log.raw(` ${c.accent.bold(p.name)} ${c.dim('by ' + p.author)} ${stars(p.stars)} ${c.cyan(dl(p.downloads) + ' dl')} ${c.dim('v' + p.version)}`);
23
+ if (p.description)
24
+ log.raw(` ${c.dim(p.description)}`);
25
+ log.raw(` ${c.dim('→')} ${c.blue('pnx plugin install ' + p.slug)}\n`);
26
+ }
27
+ if (resp.count > resp.plugins.length)
28
+ log.info(`${resp.plugins.length}/${resp.count}`);
29
+ outro('');
30
+ }
31
+ catch (e) {
32
+ sp.fail(t('plugin.fetchError', e.message));
33
+ }
34
+ }
35
+ export const listCmd = defineCommand({
36
+ meta: { description: 'List available plugins' },
37
+ args: {
38
+ sort: { type: 'string', description: 'Sort: newest|updated|stars' },
39
+ limit: { type: 'string', description: 'Results per page', default: '20' },
40
+ page: { type: 'string', description: 'Page number', default: '1' },
41
+ query: { type: 'string', description: 'Search query' },
42
+ },
43
+ run: ({ args }) => renderList({
44
+ sort: args.sort,
45
+ limit: parseInt(args.limit),
46
+ page: parseInt(args.page),
47
+ q: args.query,
48
+ }),
49
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandDef } from 'citty';
2
+ export declare const removeCmd: CommandDef;
@@ -0,0 +1,45 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, rm } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { defineCommand } from 'citty';
5
+ import { intro, outro, log } from '../../ui/output.js';
6
+ import { promptMulti, promptConfirm } from '../../ui/prompts.js';
7
+ import { resolveServerDir } from '../../services/server.js';
8
+ import { removeInstalled } from '../../services/plugins.js';
9
+ import { t } from '../../i18n/index.js';
10
+ export const removeCmd = defineCommand({
11
+ meta: { description: 'Remove installed plugins' },
12
+ args: { names: { type: 'positional', description: 'Plugin names', required: false } },
13
+ async run({ args }) {
14
+ const serverPath = (await resolveServerDir()) ?? '.';
15
+ const pluginsDir = join(serverPath, 'plugins');
16
+ if (!existsSync(pluginsDir)) {
17
+ log.error(t('plugin.noPluginsDir'));
18
+ return;
19
+ }
20
+ const jars = (await readdir(pluginsDir)).filter(f => f.endsWith('.jar'));
21
+ if (jars.length === 0) {
22
+ log.warn(t('plugin.noPlugins'));
23
+ return;
24
+ }
25
+ let names = args.names ? [args.names] : [];
26
+ if (names.length === 0) {
27
+ names = await promptMulti(t('plugin.selectRemove'), jars.map(j => ({ value: j, label: j.replace('.jar', '') })));
28
+ }
29
+ intro(`🗑️ ${t('plugin.titleRemove')}`);
30
+ for (const name of names) {
31
+ const target = name.endsWith('.jar') ? name : `${name}.jar`;
32
+ const found = jars.find(j => j.toLowerCase() === target.toLowerCase());
33
+ if (!found) {
34
+ log.warn(t('plugin.notFound', name));
35
+ continue;
36
+ }
37
+ if (await promptConfirm(t('plugin.removeConfirm', found), false)) {
38
+ await rm(join(pluginsDir, found));
39
+ await removeInstalled(found.replace('.jar', ''));
40
+ log.success(t('plugin.removed', found));
41
+ }
42
+ }
43
+ outro('');
44
+ },
45
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandDef } from 'citty';
2
+ export declare const searchCmd: CommandDef;
@@ -0,0 +1,12 @@
1
+ import { defineCommand } from 'citty';
2
+ import { promptText } from '../../ui/prompts.js';
3
+ import { renderList } from './list.js';
4
+ import { t } from '../../i18n/index.js';
5
+ export const searchCmd = defineCommand({
6
+ meta: { description: 'Search plugins' },
7
+ args: { term: { type: 'positional', description: 'Search term', required: false } },
8
+ async run({ args }) {
9
+ const term = args.term ?? await promptText({ message: t('plugin.searchPrompt') });
10
+ await renderList({ q: term, limit: 20, page: 1 });
11
+ },
12
+ });
@@ -0,0 +1,2 @@
1
+ import type { CommandDef } from 'citty';
2
+ export declare const updateCmd: CommandDef;
@@ -0,0 +1,53 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { defineCommand } from 'citty';
5
+ import { intro, outro, log, spin, progress } from '../../ui/output.js';
6
+ import { promptMulti } from '../../ui/prompts.js';
7
+ import { resolveServerDir } from '../../services/server.js';
8
+ import { getInstalled, updatePlugin } from '../../services/plugins.js';
9
+ import { t } from '../../i18n/index.js';
10
+ export const updateCmd = defineCommand({
11
+ meta: { description: 'Update installed plugins' },
12
+ args: { names: { type: 'positional', description: 'Plugin slugs', required: false } },
13
+ async run({ args }) {
14
+ const serverPath = (await resolveServerDir()) ?? '.';
15
+ const pluginsDir = join(serverPath, 'plugins');
16
+ if (!existsSync(pluginsDir)) {
17
+ log.error(t('plugin.noPluginsDir'));
18
+ return;
19
+ }
20
+ const jars = (await readdir(pluginsDir)).filter(f => f.endsWith('.jar'));
21
+ let names = args.names ? [args.names] : [];
22
+ if (names.length === 0) {
23
+ names = await promptMulti(t('plugin.selectUpdate'), jars.map(j => ({ value: j.replace('.jar', ''), label: j.replace('.jar', '') })));
24
+ }
25
+ intro(`🔄 ${t('plugin.titleUpdate')}`);
26
+ const tracked = await getInstalled();
27
+ for (const slug of names) {
28
+ const sp = spin(slug);
29
+ try {
30
+ const meta = tracked.find(p => p.slug === slug);
31
+ const existingJar = jars.find(j => j.toLowerCase().startsWith(slug.toLowerCase()));
32
+ const entry = await updatePlugin(slug, pluginsDir, meta?.version, existingJar, (pct, f) => progress(pct, f));
33
+ if (!entry) {
34
+ sp.stop(t('plugin.alreadyLatest', slug, meta?.version ?? '?'));
35
+ continue;
36
+ }
37
+ sp.stop(`${entry.name} v${entry.version}`);
38
+ log.success(t('plugin.updated', entry.name, entry.version));
39
+ }
40
+ catch (e) {
41
+ const msg = e.message;
42
+ if (msg.startsWith('no-release'))
43
+ sp.fail(t('plugin.noRelease', slug));
44
+ else if (msg.startsWith('no-file'))
45
+ sp.fail(t('plugin.noFile', slug));
46
+ else
47
+ sp.fail(t('plugin.installError', slug));
48
+ }
49
+ }
50
+ log.info(t('plugin.restartHint'));
51
+ outro('');
52
+ },
53
+ });
@@ -1,12 +1 @@
1
- export declare function pluginListCmd(options?: {
2
- sort?: string;
3
- limit?: number;
4
- page?: number;
5
- q?: string;
6
- }): Promise<void>;
7
- export declare function pluginSearchCmd(term?: string): Promise<void>;
8
- export declare function pluginInfoCmd(slug?: string): Promise<void>;
9
- export declare function pluginInstallCmd(names: string[]): Promise<void>;
10
- export declare function pluginInstalledCmd(): Promise<void>;
11
- export declare function pluginRemoveCmd(names: string[]): Promise<void>;
12
- export declare function pluginUpdateCmd(names: string[]): Promise<void>;
1
+ export {};