icoa-cli 2.19.63 → 2.19.65

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/dist/index.js CHANGED
@@ -65,19 +65,53 @@ process.on('unhandledRejection', (reason) => {
65
65
  console.error(chalk.red('Error:'), msg);
66
66
  process.exit(1);
67
67
  });
68
+ // Pause for ms, skippable by any key press (so users can read the banner)
69
+ async function pauseWithSkip(ms) {
70
+ const stdin = process.stdin;
71
+ if (!stdin.isTTY || typeof stdin.setRawMode !== 'function') {
72
+ await new Promise((r) => setTimeout(r, ms));
73
+ return;
74
+ }
75
+ return new Promise((resolve) => {
76
+ let done = false;
77
+ const finish = () => {
78
+ if (done)
79
+ return;
80
+ done = true;
81
+ stdin.removeListener('data', onKey);
82
+ try {
83
+ stdin.setRawMode(false);
84
+ }
85
+ catch { }
86
+ stdin.pause();
87
+ resolve();
88
+ };
89
+ const onKey = () => finish();
90
+ stdin.setRawMode(true);
91
+ stdin.resume();
92
+ stdin.once('data', onKey);
93
+ console.log(chalk.gray(' (press any key to continue...)'));
94
+ setTimeout(finish, ms);
95
+ });
96
+ }
68
97
  const program = new Command();
69
98
  program
70
99
  .name('icoa')
71
100
  .version('1.2.0')
72
101
  .description('ICOA CLI — CLI-Native CTF Competition Terminal')
73
102
  .option('--resume', 'Resume previous session')
74
- .action((opts) => {
103
+ .action(async (opts) => {
75
104
  // Force hacker theme: black background + green text
76
105
  setTerminalTheme();
77
106
  checkForUpdates();
78
107
  console.log(BANNER);
79
108
  // If running interactively (no extra args or --resume), start REPL
80
109
  if (process.argv.length <= 2 || opts.resume) {
110
+ // Brief pause so users can read the banner + logo before mode selector appears
111
+ // Skip on --resume (user is coming back, doesn't need the intro)
112
+ if (!opts.resume) {
113
+ await pauseWithSkip(3000);
114
+ }
81
115
  startRepl(program, !!opts.resume);
82
116
  return;
83
117
  }
@@ -11,6 +11,29 @@ const installCmd = platform() === 'win32'
11
11
  : 'sudo npm install -g icoa-cli@latest';
12
12
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
13
  const SIX_HOURS_MS = 6 * 60 * 60 * 1000;
14
+ function versionsBehind(latest, current) {
15
+ // Count PATCH-level diff only (e.g. 2.19.40 vs 2.19.46 = 6)
16
+ const l = latest.split('.').map(Number);
17
+ const c = current.split('.').map(Number);
18
+ if (l[0] !== c[0] || l[1] !== c[1])
19
+ return -1; // major/minor diff
20
+ return (l[2] ?? 0) - (c[2] ?? 0);
21
+ }
22
+ function printUpdateBanner(current, latest) {
23
+ const behind = versionsBehind(latest, current);
24
+ const behindStr = behind > 0 ? chalk.gray(` (${behind} version${behind === 1 ? '' : 's'} behind)`) : '';
25
+ const line = chalk.yellow(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
26
+ console.log();
27
+ console.log(line);
28
+ console.log(chalk.bold.yellow(' ⬆ New version available!'));
29
+ console.log();
30
+ console.log(chalk.white(' Current: ') + chalk.gray('v' + current));
31
+ console.log(chalk.white(' Latest: ') + chalk.bold.green('v' + latest) + behindStr);
32
+ console.log();
33
+ console.log(chalk.white(' Update: ') + chalk.bold.cyan(installCmd));
34
+ console.log(line);
35
+ console.log();
36
+ }
14
37
  function isNewer(latest, current) {
15
38
  const l = latest.split('.').map(Number);
16
39
  const c = current.split('.').map(Number);
@@ -38,9 +61,7 @@ export function checkForUpdates() {
38
61
  if (Date.now() - cache.lastCheck < SIX_HOURS_MS) {
39
62
  // Still within cooldown — but show banner if cached version is newer
40
63
  if (cache.latestVersion && isNewer(cache.latestVersion, current)) {
41
- console.log(chalk.yellow(' \u2B06 Update available: ') +
42
- chalk.white('v' + current + ' \u2192 v' + cache.latestVersion) +
43
- chalk.gray(` Run: ${installCmd}`));
64
+ printUpdateBanner(current, cache.latestVersion);
44
65
  }
45
66
  return;
46
67
  }
@@ -71,9 +92,7 @@ export function checkForUpdates() {
71
92
  writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
72
93
  // Print banner if newer
73
94
  if (isNewer(latest, current)) {
74
- console.log(chalk.yellow(' \u2B06 Update available: ') +
75
- chalk.white('v' + current + ' \u2192 v' + latest) +
76
- chalk.gray(` Run: ${installCmd}`));
95
+ printUpdateBanner(current, latest);
77
96
  }
78
97
  }
79
98
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.63",
3
+ "version": "2.19.65",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {