icoa-cli 2.19.53 → 2.19.54

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.
@@ -1456,8 +1456,33 @@ export function registerExamCommand(program) {
1456
1456
  const { getRealExamState } = await import('../lib/exam-state.js');
1457
1457
  const existing = getRealExamState();
1458
1458
  if (existing) {
1459
- printWarning(`Exam "${existing.session.examName}" is already in progress.`);
1460
- printInfo('Use "exam review" or "exam submit" first.');
1459
+ const answered = Object.keys(existing.answers).length;
1460
+ const total = existing.session.questionCount;
1461
+ const existingToken = existing.session.token;
1462
+ const deadline = getExamDeadline();
1463
+ const remainingMin = deadline ? Math.max(0, Math.round((deadline.getTime() - Date.now()) / 60000)) : null;
1464
+ console.log();
1465
+ console.log(chalk.yellow(` ⚠ An exam is already in progress on this device.`));
1466
+ console.log();
1467
+ console.log(chalk.gray(' Exam: ') + chalk.white(existing.session.examName));
1468
+ if (existingToken) {
1469
+ console.log(chalk.gray(' Token: ') + chalk.white(existingToken) + (existingToken === code ? chalk.green(' (same as you just typed)') : chalk.yellow(' (different from the one you typed)')));
1470
+ }
1471
+ console.log(chalk.gray(' Answers: ') + chalk.white(`${answered}/${total}`));
1472
+ if (remainingMin !== null) {
1473
+ console.log(chalk.gray(' Time: ') + chalk.white(`${remainingMin} min remaining`));
1474
+ }
1475
+ console.log();
1476
+ console.log(chalk.bold.white(' To continue this exam:'));
1477
+ console.log(chalk.gray(' → ') + chalk.bold.cyan('exam q 1') + chalk.gray(' resume at any question'));
1478
+ console.log(chalk.gray(' → ') + chalk.bold.cyan('exam review') + chalk.gray(' see progress + flagged items'));
1479
+ console.log(chalk.gray(' → ') + chalk.bold.cyan('exam submit') + chalk.gray(' finish and submit'));
1480
+ if (existingToken && existingToken !== code) {
1481
+ console.log();
1482
+ console.log(chalk.yellow(' Note: you typed a different token. Each exam token is bound to'));
1483
+ console.log(chalk.yellow(' one device + one session. You cannot switch tokens mid-exam.'));
1484
+ }
1485
+ console.log();
1461
1486
  return;
1462
1487
  }
1463
1488
  // Gate: require exam setup
@@ -1465,6 +1490,7 @@ export function registerExamCommand(program) {
1465
1490
  console.log();
1466
1491
  printWarning('Pre-exam setup required before entering a token.');
1467
1492
  console.log(chalk.gray(' → ') + chalk.bold.cyan('exam setup'));
1493
+ console.log(chalk.gray(' Or type ') + chalk.bold.cyan('back') + chalk.gray(' to return to the main menu.'));
1468
1494
  console.log();
1469
1495
  return;
1470
1496
  }
@@ -1721,6 +1747,7 @@ export function registerExamCommand(program) {
1721
1747
  }
1722
1748
  console.log();
1723
1749
  console.log(chalk.white(' Next step: ') + chalk.bold.cyan('exam <token>'));
1750
+ console.log(chalk.gray(' Or type ') + chalk.bold.cyan('back') + chalk.gray(' to return to the main menu.'));
1724
1751
  console.log();
1725
1752
  return;
1726
1753
  }
@@ -1857,6 +1884,7 @@ export function registerExamCommand(program) {
1857
1884
  console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
1858
1885
  console.log();
1859
1886
  console.log(chalk.white(' Next step: ') + chalk.bold.cyan('exam <token>'));
1887
+ console.log(chalk.gray(' Or type ') + chalk.bold.cyan('back') + chalk.gray(' to return to the main menu.'));
1860
1888
  console.log();
1861
1889
  });
1862
1890
  // Default action: progressive onboarding dashboard
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.53",
3
+ "version": "2.19.54",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {