@voiden/runner 0.1.0-beta.6 → 2.1.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/CHANGELOG.md +20 -0
- package/bundled-runners/package.json +3 -0
- package/bundled-runners/simple-assertions-runner.js +1 -0
- package/bundled-runners/versions.json +9 -0
- package/bundled-runners/voiden-advanced-auth-runner.js +1 -0
- package/bundled-runners/voiden-faker-runner.js +16 -0
- package/bundled-runners/voiden-graphql-runner.js +1 -0
- package/bundled-runners/voiden-rest-api-runner.js +1 -0
- package/bundled-runners/voiden-scripting-runner.js +397 -0
- package/bundled-runners/voiden-sockets-grpcs-runner.js +1 -0
- package/dist/cliElectron.d.ts +1 -1
- package/dist/index.js +267 -26
- package/dist/index.js.map +1 -1
- package/dist/plugins/community.d.ts +4 -3
- package/dist/plugins/community.d.ts.map +1 -1
- package/dist/plugins/community.js +32 -21
- package/dist/plugins/community.js.map +1 -1
- package/dist/plugins/loader.d.ts +9 -0
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +93 -8
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/registry.d.ts +30 -21
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +111 -46
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/registryCache.d.ts +30 -0
- package/dist/plugins/registryCache.d.ts.map +1 -0
- package/dist/plugins/registryCache.js +95 -0
- package/dist/plugins/registryCache.js.map +1 -0
- package/dist/plugins/store.d.ts +6 -1
- package/dist/plugins/store.d.ts.map +1 -1
- package/dist/plugins/store.js +21 -1
- package/dist/plugins/store.js.map +1 -1
- package/dist/plugins/updateCheck.d.ts +19 -0
- package/dist/plugins/updateCheck.d.ts.map +1 -0
- package/dist/plugins/updateCheck.js +60 -0
- package/dist/plugins/updateCheck.js.map +1 -0
- package/dist/runner.d.ts +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +19 -2
- package/dist/runner.js.map +1 -1
- package/dist/runtimeVars.d.ts +5 -0
- package/dist/runtimeVars.d.ts.map +1 -1
- package/dist/runtimeVars.js +36 -2
- package/dist/runtimeVars.js.map +1 -1
- package/package.json +13 -6
package/dist/index.js
CHANGED
|
@@ -9,9 +9,11 @@ import { runVoidFile } from './runner.js';
|
|
|
9
9
|
import { loadEnabledPlugins } from './plugins/loader.js';
|
|
10
10
|
import { exportToCsv } from './report/csv.js';
|
|
11
11
|
import { sendMailReport } from './report/mail.js';
|
|
12
|
-
import {
|
|
12
|
+
import { getCorePlugins, findPlugin, hasCoreRunner } from './plugins/registry.js';
|
|
13
|
+
import { downloadCoreRunner } from './plugins/loader.js';
|
|
13
14
|
import { fetchCommunityPlugins, findCommunityPlugin, hasCommunityRunner, installCommunityRunner, } from './plugins/community.js';
|
|
14
|
-
import { installPlugin, uninstallPlugin, setPluginEnabled, getAllInstalledPlugins, readStore, STORE_DIR, } from './plugins/store.js';
|
|
15
|
+
import { installPlugin, uninstallPlugin, setPluginEnabled, setPluginVersion, getAllInstalledPlugins, readStore, STORE_DIR, } from './plugins/store.js';
|
|
16
|
+
import { checkForPluginUpdates } from './plugins/updateCheck.js';
|
|
15
17
|
import { appendSessionResults, loadSessionResults, clearSession, } from './session.js';
|
|
16
18
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
19
|
// Helpers
|
|
@@ -278,6 +280,72 @@ function printRunSummaryJson(results, totalMs, activePlugins) {
|
|
|
278
280
|
};
|
|
279
281
|
console.log(JSON.stringify(output, null, 2));
|
|
280
282
|
}
|
|
283
|
+
/** Split CHANGELOG.md into per-version entries on "## " headers (newest first, matching file order). */
|
|
284
|
+
function parseChangelog(content) {
|
|
285
|
+
const lines = content.split('\n');
|
|
286
|
+
const entries = [];
|
|
287
|
+
let current = null;
|
|
288
|
+
for (const line of lines) {
|
|
289
|
+
const headerMatch = line.match(/^##\s+(\S+)(?:\s+-\s+(.+))?$/);
|
|
290
|
+
if (headerMatch) {
|
|
291
|
+
if (current)
|
|
292
|
+
entries.push(current);
|
|
293
|
+
current = { version: headerMatch[1], date: headerMatch[2]?.trim(), body: [] };
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (current)
|
|
297
|
+
current.body.push(line);
|
|
298
|
+
}
|
|
299
|
+
if (current)
|
|
300
|
+
entries.push(current);
|
|
301
|
+
return entries;
|
|
302
|
+
}
|
|
303
|
+
function renderChangelogEntry(entry) {
|
|
304
|
+
const header = entry.date ? `${entry.version} ${chalk.gray(entry.date)}` : entry.version;
|
|
305
|
+
console.log(chalk.bold.white(` ${header}`));
|
|
306
|
+
console.log(DIVIDER);
|
|
307
|
+
for (const line of entry.body) {
|
|
308
|
+
const trimmed = line.trim();
|
|
309
|
+
if (!trimmed)
|
|
310
|
+
continue;
|
|
311
|
+
const sectionMatch = trimmed.match(/^###\s+(.+)$/);
|
|
312
|
+
if (sectionMatch) {
|
|
313
|
+
console.log();
|
|
314
|
+
console.log(chalk.bold.cyan(` ${sectionMatch[1]}`));
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const bulletMatch = trimmed.match(/^-\s+(.+)$/);
|
|
318
|
+
if (bulletMatch) {
|
|
319
|
+
console.log(chalk.gray(` · `) + bulletMatch[1]);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
console.log(` ${trimmed}`);
|
|
323
|
+
}
|
|
324
|
+
console.log();
|
|
325
|
+
}
|
|
326
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
327
|
+
// Plugin update notices — surfaced after `run` and `plugin` commands so users
|
|
328
|
+
// learn about newer registry versions without having to run `plugin list`.
|
|
329
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
330
|
+
function printUpdateNotice(updates) {
|
|
331
|
+
if (updates.length === 0)
|
|
332
|
+
return;
|
|
333
|
+
console.log();
|
|
334
|
+
console.log(chalk.yellow(` ⬆ ${updates.length} plugin update${updates.length !== 1 ? 's' : ''} available`));
|
|
335
|
+
for (const u of updates) {
|
|
336
|
+
console.log(chalk.gray(` ${chalk.bold(u.id.padEnd(24))} ${u.installedVersion} → ${chalk.green(u.latestVersion)}`));
|
|
337
|
+
}
|
|
338
|
+
console.log(chalk.gray(` Run: voiden-runner plugin update --all`));
|
|
339
|
+
}
|
|
340
|
+
/** Best-effort update check — never throws, never blocks command output on failure. */
|
|
341
|
+
async function notifyPluginUpdates() {
|
|
342
|
+
try {
|
|
343
|
+
printUpdateNotice(await checkForPluginUpdates());
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
// Informational only — ignore failures (e.g. offline)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
281
349
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
282
350
|
// CLI
|
|
283
351
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -287,6 +355,47 @@ program
|
|
|
287
355
|
.name('voiden-runner')
|
|
288
356
|
.description('Run .void files headlessly — REST, WebSocket, and gRPC')
|
|
289
357
|
.version(pkg.version);
|
|
358
|
+
// ── voiden-runner changelog ───────────────────────────────────────────────────
|
|
359
|
+
program
|
|
360
|
+
.command('changelog [version]')
|
|
361
|
+
.description('Show release notes for voiden-runner — versioned independently of the desktop app\n\n' +
|
|
362
|
+
' Examples:\n' +
|
|
363
|
+
' voiden-runner changelog # full history\n' +
|
|
364
|
+
' voiden-runner changelog --latest # most recent release only\n' +
|
|
365
|
+
' voiden-runner changelog 2.1.0 # a specific version\n')
|
|
366
|
+
.option('--latest', 'Show only the most recent release')
|
|
367
|
+
.action((version, opts) => {
|
|
368
|
+
const changelogPath = resolve(join(dirname(fileURLToPath(import.meta.url)), '../CHANGELOG.md'));
|
|
369
|
+
if (!existsSync(changelogPath)) {
|
|
370
|
+
console.error(chalk.red(' ✗ No CHANGELOG.md found for this install.'));
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
const entries = parseChangelog(readFileSync(changelogPath, 'utf-8'));
|
|
374
|
+
if (entries.length === 0) {
|
|
375
|
+
console.log(chalk.gray(' Changelog is empty.'));
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
let toShow = entries;
|
|
379
|
+
if (version) {
|
|
380
|
+
const normalized = version.replace(/^v/, '');
|
|
381
|
+
const match = entries.find(e => e.version.replace(/^v/, '') === normalized);
|
|
382
|
+
if (!match) {
|
|
383
|
+
console.error(chalk.red(` ✗ No changelog entry found for version "${version}".`));
|
|
384
|
+
console.log(chalk.gray(` Available: ${entries.map(e => e.version).join(', ')}`));
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
toShow = [match];
|
|
388
|
+
}
|
|
389
|
+
else if (opts.latest) {
|
|
390
|
+
toShow = [entries[0]];
|
|
391
|
+
}
|
|
392
|
+
console.log();
|
|
393
|
+
console.log(chalk.bold.white(' voiden-runner changelog'));
|
|
394
|
+
console.log();
|
|
395
|
+
for (const entry of toShow) {
|
|
396
|
+
renderChangelogEntry(entry);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
290
399
|
// ── voiden-runner run ─────────────────────────────────────────────────────────
|
|
291
400
|
program
|
|
292
401
|
.command('run <paths...>')
|
|
@@ -541,6 +650,9 @@ program
|
|
|
541
650
|
console.log(chalk.gray(' (use this exit code in your shell script to abort on failure)'));
|
|
542
651
|
console.log();
|
|
543
652
|
}
|
|
653
|
+
// Surface plugin update notices — skipped in --json mode so output stays machine-readable
|
|
654
|
+
if (!opts.json)
|
|
655
|
+
await notifyPluginUpdates();
|
|
544
656
|
process.exit(shouldFail ? 1 : 0);
|
|
545
657
|
});
|
|
546
658
|
// ── voiden-runner session ─────────────────────────────────────────────────────
|
|
@@ -765,13 +877,14 @@ pluginCmd
|
|
|
765
877
|
' voiden-runner plugin install apyhub-explorer\n')
|
|
766
878
|
.option('--all', 'Install all core plugins (community plugins must be installed by name)')
|
|
767
879
|
.action(async (names, opts) => {
|
|
880
|
+
const corePlugins = await getCorePlugins();
|
|
768
881
|
const communityPlugins = await fetchCommunityPlugins();
|
|
769
882
|
const targets = opts.all
|
|
770
|
-
?
|
|
883
|
+
? corePlugins.map(p => p.name)
|
|
771
884
|
: names;
|
|
772
885
|
if (targets.length === 0) {
|
|
773
886
|
console.error(chalk.red('Specify plugin name(s) or use --all'));
|
|
774
|
-
console.log(chalk.gray(' Core: ' +
|
|
887
|
+
console.log(chalk.gray(' Core: ' + corePlugins.map(p => p.name).join(', ')));
|
|
775
888
|
if (communityPlugins.length > 0) {
|
|
776
889
|
console.log(chalk.gray(' Community (install by name): ' + communityPlugins.map(p => p.id).join(', ')));
|
|
777
890
|
}
|
|
@@ -779,12 +892,29 @@ pluginCmd
|
|
|
779
892
|
}
|
|
780
893
|
let installedCount = 0;
|
|
781
894
|
for (const name of targets) {
|
|
782
|
-
const coreDef = findPlugin(name);
|
|
895
|
+
const coreDef = await findPlugin(name);
|
|
783
896
|
const commDef = !coreDef ? findCommunityPlugin(name, communityPlugins) : undefined;
|
|
784
897
|
if (!coreDef && !commDef) {
|
|
785
898
|
console.log(chalk.yellow(` ⚠ Unknown plugin "${name}" — skipped`));
|
|
786
899
|
continue;
|
|
787
900
|
}
|
|
901
|
+
// Core plugins: only download if not already bundled in the package or cached
|
|
902
|
+
// from a previous install — `bundled: true` plugins should need no network call.
|
|
903
|
+
if (coreDef && !hasCoreRunner(name)) {
|
|
904
|
+
process.stdout.write(` ↓ Downloading runner for ${chalk.bold(name)} …`);
|
|
905
|
+
try {
|
|
906
|
+
const ok = await downloadCoreRunner(coreDef.name, coreDef.repo, coreDef.runnerAsset, coreDef.version, false);
|
|
907
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
908
|
+
if (!ok) {
|
|
909
|
+
console.log(chalk.red(` ✗ No "${coreDef.runnerAsset}" asset in release v${coreDef.version} for "${name}"`));
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
catch (err) {
|
|
914
|
+
process.stdout.write('\r' + chalk.red(` ✗ Failed to download runner for "${name}": ${err?.message ?? String(err)}\n`));
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
788
918
|
// Community plugins: download runner.js from the GitHub release first
|
|
789
919
|
if (commDef) {
|
|
790
920
|
process.stdout.write(` ↓ Downloading runner for ${chalk.bold(name)} …`);
|
|
@@ -794,6 +924,7 @@ pluginCmd
|
|
|
794
924
|
process.stdout.write('\r' + chalk.yellow(` ⚠ No runner.js in release for "${name}" — skipped\n`));
|
|
795
925
|
continue;
|
|
796
926
|
}
|
|
927
|
+
setPluginVersion(name, commDef.version);
|
|
797
928
|
process.stdout.write('\r' + ' '.repeat(60) + '\r'); // clear the line
|
|
798
929
|
}
|
|
799
930
|
catch (err) {
|
|
@@ -802,7 +933,7 @@ pluginCmd
|
|
|
802
933
|
}
|
|
803
934
|
}
|
|
804
935
|
const description = coreDef ? coreDef.description : commDef.description;
|
|
805
|
-
const fresh = installPlugin(name);
|
|
936
|
+
const fresh = installPlugin(name, coreDef?.version ?? commDef?.version);
|
|
806
937
|
if (fresh) {
|
|
807
938
|
console.log(chalk.green(` ✓ Installed`) + chalk.bold(` ${name}`) + chalk.gray(` — ${description}`));
|
|
808
939
|
installedCount++;
|
|
@@ -815,18 +946,111 @@ pluginCmd
|
|
|
815
946
|
console.log();
|
|
816
947
|
console.log(chalk.gray(` ${installedCount} plugin(s) installed. State saved to ~/.voiden/plugins.json`));
|
|
817
948
|
}
|
|
949
|
+
await notifyPluginUpdates();
|
|
818
950
|
});
|
|
819
|
-
// voiden-runner plugin
|
|
951
|
+
// voiden-runner plugin update [names...] --all
|
|
820
952
|
pluginCmd
|
|
821
|
-
.command('
|
|
822
|
-
.description('
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
953
|
+
.command('update [names...]')
|
|
954
|
+
.description('Update installed plugins to the latest registry version\n\n' +
|
|
955
|
+
' --all updates every installed plugin that has a newer version available.\n\n' +
|
|
956
|
+
' Examples:\n' +
|
|
957
|
+
' voiden-runner plugin update --all\n' +
|
|
958
|
+
' voiden-runner plugin update voiden-scripting\n' +
|
|
959
|
+
' voiden-runner plugin update apyhub-explorer voiden-scripting\n')
|
|
960
|
+
.option('--all', 'Update every installed plugin that has a newer version available')
|
|
961
|
+
.action(async (names, opts) => {
|
|
962
|
+
const updates = await checkForPluginUpdates();
|
|
963
|
+
if (updates.length === 0) {
|
|
964
|
+
console.log(chalk.gray(' All installed plugins are up to date.'));
|
|
965
|
+
return;
|
|
827
966
|
}
|
|
828
|
-
|
|
829
|
-
|
|
967
|
+
const targets = opts.all ? updates.map(u => u.id) : names;
|
|
968
|
+
if (targets.length === 0) {
|
|
969
|
+
console.log(chalk.yellow(` ${updates.length} update${updates.length !== 1 ? 's' : ''} available — specify plugin name(s) or use --all:`));
|
|
970
|
+
printUpdateNotice(updates);
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
const corePlugins = await getCorePlugins();
|
|
974
|
+
const communityPlugins = await fetchCommunityPlugins();
|
|
975
|
+
let updatedCount = 0;
|
|
976
|
+
for (const name of targets) {
|
|
977
|
+
const update = updates.find(u => u.id === name);
|
|
978
|
+
if (!update) {
|
|
979
|
+
const known = readStore().installedPlugins[name];
|
|
980
|
+
console.log(known
|
|
981
|
+
? chalk.gray(` · ${name} is already up to date — skipped`)
|
|
982
|
+
: chalk.yellow(` ⚠ Plugin "${name}" is not installed — skipped`));
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
process.stdout.write(` ↓ Updating ${chalk.bold(name)} to v${update.latestVersion} …`);
|
|
986
|
+
try {
|
|
987
|
+
if (update.type === 'core') {
|
|
988
|
+
const def = corePlugins.find(p => p.name === name);
|
|
989
|
+
if (!def)
|
|
990
|
+
throw new Error('plugin no longer in core registry');
|
|
991
|
+
const ok = await downloadCoreRunner(def.name, def.repo, def.runnerAsset, def.version, false);
|
|
992
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
993
|
+
if (!ok) {
|
|
994
|
+
console.log(chalk.red(` ✗ No "${def.runnerAsset}" asset in release v${update.latestVersion} for "${name}"`));
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
else {
|
|
999
|
+
const def = communityPlugins.find(p => p.id === name);
|
|
1000
|
+
if (!def)
|
|
1001
|
+
throw new Error('plugin no longer in community registry');
|
|
1002
|
+
const result = await installCommunityRunner(def);
|
|
1003
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
1004
|
+
if (result === 'no-runner') {
|
|
1005
|
+
console.log(chalk.red(` ✗ No runner.js in release v${update.latestVersion} for "${name}"`));
|
|
1006
|
+
continue;
|
|
1007
|
+
}
|
|
1008
|
+
setPluginVersion(name, update.latestVersion);
|
|
1009
|
+
}
|
|
1010
|
+
console.log(chalk.green(` ✓ Updated`) + chalk.bold(` ${name}`) +
|
|
1011
|
+
chalk.gray(` ${update.installedVersion} → ${update.latestVersion}`));
|
|
1012
|
+
updatedCount++;
|
|
1013
|
+
}
|
|
1014
|
+
catch (err) {
|
|
1015
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
1016
|
+
console.log(chalk.red(` ✗ Failed to update "${name}": ${err?.message ?? String(err)}`));
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (updatedCount > 0) {
|
|
1020
|
+
console.log();
|
|
1021
|
+
console.log(chalk.gray(` ${updatedCount} plugin(s) updated.`));
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
// voiden-runner plugin uninstall [names...] --all
|
|
1025
|
+
pluginCmd
|
|
1026
|
+
.command('uninstall [names...]')
|
|
1027
|
+
.description('Remove one or more installed plugins, or all installed plugins\n\n' +
|
|
1028
|
+
' Examples:\n' +
|
|
1029
|
+
' voiden-runner plugin uninstall voiden-scripting\n' +
|
|
1030
|
+
' voiden-runner plugin uninstall apyhub-explorer voiden-scripting\n' +
|
|
1031
|
+
' voiden-runner plugin uninstall --all\n')
|
|
1032
|
+
.option('--all', 'Uninstall all installed plugins (core and community)')
|
|
1033
|
+
.action((names, opts) => {
|
|
1034
|
+
const targets = opts.all ? Object.keys(readStore().installedPlugins) : names;
|
|
1035
|
+
if (targets.length === 0) {
|
|
1036
|
+
console.error(chalk.red(' Specify plugin name(s) or use --all'));
|
|
1037
|
+
process.exit(1);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
let removedCount = 0;
|
|
1041
|
+
for (const name of targets) {
|
|
1042
|
+
const removed = uninstallPlugin(name);
|
|
1043
|
+
if (removed) {
|
|
1044
|
+
console.log(chalk.green(` ✓ Uninstalled`) + ` ${name}`);
|
|
1045
|
+
removedCount++;
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
console.log(chalk.yellow(` ⚠ Plugin "${name}" is not installed`));
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
if (removedCount > 1) {
|
|
1052
|
+
console.log();
|
|
1053
|
+
console.log(chalk.gray(` ${removedCount} plugin(s) uninstalled.`));
|
|
830
1054
|
}
|
|
831
1055
|
});
|
|
832
1056
|
// voiden-runner plugin enable [name] --all
|
|
@@ -879,31 +1103,34 @@ pluginCmd
|
|
|
879
1103
|
' voiden-runner plugin disable voiden-scripting\n' +
|
|
880
1104
|
' voiden-runner plugin disable --all\n')
|
|
881
1105
|
.option('--all', 'Disable all plugins (core and community)')
|
|
882
|
-
.action((name, opts) => {
|
|
1106
|
+
.action(async (name, opts) => {
|
|
1107
|
+
const corePlugins = await getCorePlugins();
|
|
883
1108
|
if (opts.all) {
|
|
884
1109
|
// Disable all core plugins
|
|
885
|
-
for (const def of
|
|
1110
|
+
for (const def of corePlugins) {
|
|
886
1111
|
setPluginEnabled(def.name, false);
|
|
887
1112
|
console.log(chalk.yellow(` · Disabled`) + ` ${def.name}`);
|
|
888
1113
|
}
|
|
889
1114
|
// Disable all installed community plugins
|
|
890
1115
|
const store = readStore();
|
|
891
|
-
const
|
|
1116
|
+
const coreNames = new Set(corePlugins.map(p => p.name));
|
|
1117
|
+
const communityNames = Object.keys(store.installedPlugins).filter(n => !coreNames.has(n));
|
|
892
1118
|
for (const n of communityNames) {
|
|
893
1119
|
setPluginEnabled(n, false);
|
|
894
1120
|
console.log(chalk.yellow(` · Disabled`) + ` ${n}`);
|
|
895
1121
|
}
|
|
896
|
-
const total =
|
|
1122
|
+
const total = corePlugins.length + communityNames.length;
|
|
897
1123
|
console.log(chalk.gray(` ${total} plugin(s) disabled.`));
|
|
898
1124
|
return;
|
|
899
1125
|
}
|
|
900
1126
|
if (!name) {
|
|
901
1127
|
console.error(chalk.red(' Specify a plugin name or use --all'));
|
|
902
1128
|
process.exit(1);
|
|
1129
|
+
return;
|
|
903
1130
|
}
|
|
904
1131
|
setPluginEnabled(name, false);
|
|
905
1132
|
console.log(chalk.yellow(` · Disabled`) + ` ${name}`);
|
|
906
|
-
if (findPlugin(name)) {
|
|
1133
|
+
if (await findPlugin(name)) {
|
|
907
1134
|
console.log(chalk.gray(` Core plugin disabled. Re-enable with: voiden-runner plugin enable ${name}`));
|
|
908
1135
|
}
|
|
909
1136
|
});
|
|
@@ -913,17 +1140,26 @@ pluginCmd
|
|
|
913
1140
|
.description('List all available and installed plugins')
|
|
914
1141
|
.action(async () => {
|
|
915
1142
|
const store = readStore();
|
|
1143
|
+
const corePlugins = await getCorePlugins();
|
|
916
1144
|
const communityPlugins = await fetchCommunityPlugins();
|
|
1145
|
+
// Per-plugin "update available" badge — compares the version recorded at
|
|
1146
|
+
// install/download time against the registry's current version.
|
|
1147
|
+
const updateBadge = (id, latestVersion) => {
|
|
1148
|
+
const installedVersion = store.installedPlugins[id]?.version;
|
|
1149
|
+
if (!installedVersion || installedVersion === latestVersion)
|
|
1150
|
+
return '';
|
|
1151
|
+
return chalk.yellow(` ⬆ v${latestVersion} available`);
|
|
1152
|
+
};
|
|
917
1153
|
console.log();
|
|
918
|
-
console.log(chalk.bold(' Core plugins') + chalk.gray(' (
|
|
1154
|
+
console.log(chalk.bold(' Core plugins') + chalk.gray(' (from VoidenHQ/plugin-registry)'));
|
|
919
1155
|
console.log(DIVIDER);
|
|
920
|
-
for (const def of
|
|
1156
|
+
for (const def of corePlugins) {
|
|
921
1157
|
const record = store.installedPlugins[def.name];
|
|
922
1158
|
const isDisabled = record !== undefined && !record.enabled;
|
|
923
1159
|
const statusBadge = isDisabled
|
|
924
1160
|
? chalk.yellow(' · disabled')
|
|
925
1161
|
: chalk.green(' ✓ enabled');
|
|
926
|
-
console.log(` ${chalk.bold(def.name.padEnd(24))}${statusBadge}`);
|
|
1162
|
+
console.log(` ${chalk.bold(def.name.padEnd(24))}${statusBadge}${updateBadge(def.name, def.version)}`);
|
|
927
1163
|
console.log(chalk.gray(` ${def.description}`));
|
|
928
1164
|
}
|
|
929
1165
|
// ── Community plugins ───────────────────────────────────────────────────
|
|
@@ -933,7 +1169,7 @@ pluginCmd
|
|
|
933
1169
|
console.log(DIVIDER);
|
|
934
1170
|
}
|
|
935
1171
|
else {
|
|
936
|
-
console.log(chalk.bold(' Community plugins') + chalk.gray(' (
|
|
1172
|
+
console.log(chalk.bold(' Community plugins') + chalk.gray(' (from VoidenHQ/plugin-registry)'));
|
|
937
1173
|
console.log(DIVIDER);
|
|
938
1174
|
for (const def of communityPlugins) {
|
|
939
1175
|
const installed = store.installedPlugins[def.id];
|
|
@@ -948,14 +1184,14 @@ pluginCmd
|
|
|
948
1184
|
statusBadge = chalk.yellow(' · disabled');
|
|
949
1185
|
}
|
|
950
1186
|
const runnerBadge = hasCommunityRunner(def.id) ? '' : chalk.gray(' [no runner]');
|
|
951
|
-
console.log(` ${chalk.bold(def.id.padEnd(24))}${statusBadge}${runnerBadge}` +
|
|
1187
|
+
console.log(` ${chalk.bold(def.id.padEnd(24))}${statusBadge}${runnerBadge}${updateBadge(def.id, def.version)}` +
|
|
952
1188
|
chalk.gray(` v${def.version}`) +
|
|
953
1189
|
chalk.gray(` by ${def.author}`));
|
|
954
1190
|
console.log(chalk.gray(` ${def.description}`));
|
|
955
1191
|
}
|
|
956
1192
|
}
|
|
957
1193
|
const knownIds = new Set([
|
|
958
|
-
...
|
|
1194
|
+
...corePlugins.map(p => p.name),
|
|
959
1195
|
...communityPlugins.map(p => p.id),
|
|
960
1196
|
]);
|
|
961
1197
|
const extras = getAllInstalledPlugins().filter(p => !knownIds.has(p.name));
|
|
@@ -968,6 +1204,11 @@ pluginCmd
|
|
|
968
1204
|
console.log(` ${chalk.bold(p.name.padEnd(24))}${badge}`);
|
|
969
1205
|
}
|
|
970
1206
|
}
|
|
1207
|
+
const updates = await checkForPluginUpdates();
|
|
1208
|
+
if (updates.length > 0) {
|
|
1209
|
+
console.log();
|
|
1210
|
+
console.log(chalk.gray(` Run: voiden-runner plugin update --all (${updates.length} update${updates.length !== 1 ? 's' : ''} available)`));
|
|
1211
|
+
}
|
|
971
1212
|
console.log();
|
|
972
1213
|
});
|
|
973
1214
|
program.parse();
|