icoa-cli 2.16.7 โ†’ 2.16.9

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.
@@ -516,7 +516,7 @@ export function registerExamCommand(program) {
516
516
  exam
517
517
  .command('answer <n> <choice>')
518
518
  .description('Answer question N with choice A/B/C/D')
519
- .action((n, choice) => {
519
+ .action(async (n, choice) => {
520
520
  logCommand(`exam answer ${n} ${choice}`);
521
521
  const state = getExamState();
522
522
  if (!state) {
@@ -561,10 +561,69 @@ export function registerExamCommand(program) {
561
561
  saveExamState(state);
562
562
  printQuestion(nextQ, state.answers[nextQ.number]);
563
563
  }
564
- else if (answered === total) {
564
+ else if (answered >= state.questions.length) {
565
565
  console.log();
566
566
  console.log(chalk.green.bold(' ๐ŸŽ‰ All questions answered!'));
567
- console.log(chalk.white(' Use: exam review ยท exam submit'));
567
+ console.log();
568
+ if (state.session.examId === 'demo-free') {
569
+ console.log(chalk.white(' Auto-submitting your demo...'));
570
+ console.log();
571
+ // Auto-submit demo
572
+ try {
573
+ const { DEMO_ANSWERS } = await import('../lib/demo-exam.js');
574
+ drawProgress(0, 'Grading...');
575
+ await sleep(300);
576
+ let score = 0;
577
+ for (const [qn, ans] of Object.entries(state.answers)) {
578
+ if (DEMO_ANSWERS[Number(qn)] === ans)
579
+ score++;
580
+ }
581
+ drawProgress(100, 'Complete!');
582
+ console.log();
583
+ clearExamState();
584
+ const pct = Math.round(score / state.questions.length * 100);
585
+ console.log();
586
+ console.log(chalk.cyan(' โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'));
587
+ console.log();
588
+ console.log(chalk.bold.white(' โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—'));
589
+ console.log(chalk.bold.white(' โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—'));
590
+ console.log(chalk.bold.white(' โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘'));
591
+ console.log(chalk.bold.white(' โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘'));
592
+ console.log(chalk.bold.white(' โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘'));
593
+ console.log(chalk.bold.white(' โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•'));
594
+ console.log();
595
+ console.log(chalk.bold(` Score: ${score}/${state.questions.length} (${pct}%)`));
596
+ console.log(chalk.bold(` ${pct >= 60 ? chalk.green('โœ“ PASSED') : chalk.red('โœ— NOT PASSED')}`));
597
+ console.log();
598
+ console.log(chalk.yellow(' International Cyber Olympiad in AI 2026'));
599
+ console.log(chalk.gray(' Sydney, Australia ยท Jun 27 - Jul 2, 2026'));
600
+ console.log();
601
+ console.log(chalk.cyan(' โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'));
602
+ console.log();
603
+ console.log(chalk.white(' Nice work! Those were the theory questions.'));
604
+ console.log();
605
+ console.log(chalk.yellow(' Did you know?'));
606
+ console.log(chalk.gray(' CTF stands for "Capture The Flag" โ€” a cybersecurity'));
607
+ console.log(chalk.gray(' competition where you solve real hacking challenges.'));
608
+ console.log();
609
+ console.log(chalk.white(' ICOA combines CTF with AI in ') + chalk.bold('TWO') + chalk.white(' tracks:'));
610
+ console.log();
611
+ console.log(chalk.green.bold(' AI4CTF') + chalk.white(' โ€” Use AI to help you solve CTF challenges'));
612
+ console.log(chalk.gray(' AI is your teammate. Chat, ask for hints, work together.'));
613
+ console.log();
614
+ console.log(chalk.red.bold(' CTF4AI') + chalk.white(' โ€” Trick the AI (Prompt Injection)'));
615
+ console.log(chalk.gray(' Can you make the AI break its own safety rules?'));
616
+ console.log();
617
+ console.log(chalk.white(' Try them now:'));
618
+ console.log(chalk.green.bold(' ai4ctf') + chalk.gray(' Chat with AI teammate (start here!)'));
619
+ console.log(chalk.red.bold(' ctf4ai') + chalk.gray(' Trick the AI โ€” make it say "koala"'));
620
+ console.log();
621
+ }
622
+ catch { }
623
+ }
624
+ else {
625
+ console.log(chalk.white(' Use: exam review ยท exam submit'));
626
+ }
568
627
  }
569
628
  });
570
629
  // โ”€โ”€โ”€ exam review โ”€โ”€โ”€
@@ -638,14 +697,17 @@ export function registerExamCommand(program) {
638
697
  }
639
698
  return;
640
699
  }
641
- let msg = `Submit ${answered}/${total} answers?`;
642
- if (unanswered > 0) {
643
- msg += chalk.yellow(` ${unanswered} unanswered.`);
700
+ // Demo: submit directly. Real exam: show warning first.
701
+ if (state.session.examId !== 'demo-free') {
702
+ console.log();
703
+ console.log(chalk.yellow(` Submitting ${answered}/${total} answers.`));
704
+ if (unanswered > 0) {
705
+ console.log(chalk.yellow(` ${unanswered} unanswered.`));
706
+ }
707
+ console.log(chalk.gray(' You cannot change answers after this.'));
708
+ console.log(chalk.gray(' Type "back" now to cancel, or wait...'));
709
+ await sleep(2000);
644
710
  }
645
- msg += ' You cannot change answers after this.';
646
- const proceed = await confirm({ message: chalk.white(msg), default: false, theme: { prefix: '', style: { message: (t) => t, defaultAnswer: (t) => chalk.green(t) } } });
647
- if (!proceed)
648
- return;
649
711
  console.log();
650
712
  // Demo exam: grade locally
651
713
  if (state.session.examId === 'demo-free') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.16.7",
3
+ "version": "2.16.9",
4
4
  "description": "ICOA CLI โ€” The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {