icoa-cli 2.15.0 → 2.15.2

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.
@@ -121,6 +121,38 @@ function printQuestion(q, answer) {
121
121
  }
122
122
  export function registerExamCommand(program) {
123
123
  const exam = program.command('exam').description('National selection exam');
124
+ // ─── exam nations ───
125
+ exam
126
+ .command('nations')
127
+ .description('View all participating countries')
128
+ .action(() => {
129
+ logCommand('exam nations');
130
+ console.log();
131
+ printHeader('ICOA Participating Countries');
132
+ console.log();
133
+ const nations = [
134
+ ['AU', 'Australia'], ['BR', 'Brazil'], ['CN', 'China'],
135
+ ['DE', 'Germany'], ['EG', 'Egypt'], ['FR', 'France'],
136
+ ['ID', 'Indonesia'], ['IN', 'India'], ['JP', 'Japan'],
137
+ ['KR', 'South Korea'], ['MY', 'Malaysia'], ['PE', 'Peru'],
138
+ ['PH', 'Philippines'], ['RU', 'Russia'], ['SA', 'Saudi Arabia'],
139
+ ['SG', 'Singapore'], ['TH', 'Thailand'], ['TR', 'Turkey'],
140
+ ['VN', 'Vietnam'], ['ZA', 'South Africa'],
141
+ ];
142
+ for (let i = 0; i < nations.length; i += 3) {
143
+ const row = nations.slice(i, i + 3)
144
+ .map(([code, name]) => ` ${chalk.cyan(code)} ${chalk.gray(name.padEnd(16))}`)
145
+ .join('');
146
+ console.log(row);
147
+ }
148
+ console.log();
149
+ console.log(chalk.gray(' 40+ countries and regions accredited'));
150
+ console.log(chalk.gray(' New country? Contact: accreditation@icoa2026.au'));
151
+ console.log();
152
+ console.log(chalk.white(' Check exams for your country:'));
153
+ console.log(chalk.cyan(' exam list AU') + chalk.gray(' exam list PE') + chalk.gray(' exam list CN'));
154
+ console.log();
155
+ });
124
156
  // ─── exam list [country] ───
125
157
  exam
126
158
  .command('list [country]')
@@ -610,20 +642,37 @@ export function registerExamCommand(program) {
610
642
  console.log();
611
643
  console.log(chalk.cyan(' ═══════════════════════════════════════'));
612
644
  console.log();
613
- // ─── Dual-track introduction ───
614
- console.log(chalk.white(' Nice work! ICOA has ') + chalk.bold('TWO') + chalk.white(' competition tracks:'));
645
+ // ─── What is CTF + Dual-track introduction ───
646
+ console.log(chalk.white(' Nice work! Those were the theory questions.'));
647
+ console.log();
648
+ console.log(chalk.yellow(' Did you know?'));
649
+ console.log(chalk.gray(' CTF stands for "Capture The Flag" — a cybersecurity'));
650
+ console.log(chalk.gray(' competition where you solve real hacking challenges'));
651
+ console.log(chalk.gray(' like cracking codes, finding hidden data, and'));
652
+ console.log(chalk.gray(' exploiting vulnerabilities in safe environments.'));
653
+ console.log();
654
+ console.log(chalk.white(' ICOA combines CTF with AI in ') + chalk.bold('TWO') + chalk.white(' tracks:'));
655
+ console.log();
656
+ console.log(chalk.green.bold(' AI4CTF') + chalk.white(' — Use AI to help you solve CTF challenges'));
657
+ console.log(chalk.gray(' AI is your teammate. Chat with it, ask for hints,'));
658
+ console.log(chalk.gray(' and work together to crack cybersecurity puzzles.'));
659
+ console.log();
660
+ console.log(chalk.red.bold(' CTF4AI') + chalk.white(' — Trick the AI (Prompt Injection)'));
661
+ console.log(chalk.gray(' Can you make the AI break its own safety rules?'));
662
+ console.log(chalk.gray(' This is a real skill used to test AI security.'));
615
663
  console.log();
616
- console.log(chalk.green.bold(' AI4CTF') + chalk.white(' — Solve problems with AI help'));
617
- console.log(chalk.gray(' The AI is your teammate. Ask questions, get hints,'));
618
- console.log(chalk.gray(' work together to solve cybersecurity challenges.'));
664
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
665
+ console.log(chalk.gray(' In the real ICOA competition, everything happens'));
666
+ console.log(chalk.gray(' inside this terminal. No other tools allowed.'));
667
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
619
668
  console.log();
620
- console.log(chalk.red.bold(' CTF4AI') + chalk.white(' Hack the AI itself'));
621
- console.log(chalk.gray(' Can you trick the AI into breaking its own rules?'));
622
- console.log(chalk.gray(' Try to make it say a forbidden word!'));
669
+ console.log(chalk.white(' Ready to try? Type a command:'));
670
+ console.log(chalk.green.bold(' ai4ctf') + chalk.gray(' Chat with AI teammate (start here!)'));
671
+ console.log(chalk.red.bold(' ctf4ai') + chalk.gray(' Trick the AI — make it say "koala"'));
623
672
  console.log();
624
- console.log(chalk.white(' Try them now:'));
625
- console.log(chalk.green.bold(' ai4ctf') + chalk.gray(' Chat with your AI teammate (try this first!)'));
626
- console.log(chalk.red.bold(' ctf4ai') + chalk.gray(' Challenge: make AI say "koala"'));
673
+ console.log(chalk.gray(' For national selection exams:'));
674
+ console.log(chalk.white(' nations') + chalk.gray(' View all country codes'));
675
+ console.log(chalk.white(' exam AU') + chalk.gray(' Enter Australia selection exam'));
627
676
  console.log();
628
677
  }
629
678
  catch (err) {
package/dist/repl.js CHANGED
@@ -365,6 +365,18 @@ export async function startRepl(program, resumeMode) {
365
365
  rl.prompt();
366
366
  return;
367
367
  }
368
+ // "exam AU" / "exam PE" — shortcut to exam list <country>
369
+ const examCountryMatch = input.match(/^exam\s+([A-Z]{2,3})$/i);
370
+ if (examCountryMatch) {
371
+ processing = true;
372
+ try {
373
+ await program.parseAsync(['node', 'icoa', 'exam', 'list', examCountryMatch[1]]);
374
+ }
375
+ catch { }
376
+ processing = false;
377
+ rl.prompt();
378
+ return;
379
+ }
368
380
  // Clear
369
381
  if (input === 'clear' || input === 'cls') {
370
382
  console.clear();
@@ -427,7 +439,7 @@ export async function startRepl(program, resumeMode) {
427
439
  }
428
440
  const cmd = input.split(/\s+/)[0].toLowerCase();
429
441
  // ─── Mode-based command filtering ───
430
- const selectionCommands = ['exam', 'demo', 'next', 'prev', 'setup', 'lang', 'ref', 'ai4ctf', 'ctf4ai'];
442
+ const selectionCommands = ['exam', 'demo', 'nations', 'next', 'prev', 'setup', 'lang', 'ref', 'ai4ctf', 'ctf4ai'];
431
443
  const organizerCommands = ['join', 'exam', 'demo', 'next', 'prev', 'logout', 'setup', 'lang', 'ref', 'ctf'];
432
444
  if (mode === 'selection' && !selectionCommands.includes(cmd)) {
433
445
  console.log(chalk.gray(' Not available in Selection mode.'));
@@ -464,7 +476,7 @@ export async function startRepl(program, resumeMode) {
464
476
  'scoreboard', 'sb', 'status', 'time', 'hint', 'hint-b', 'hint-c',
465
477
  'hint-budget', 'ref', 'shell', 'files', 'connect', 'note',
466
478
  'log', 'lang', 'setup', 'env', 'ai4ctf', 'model', 'ctf',
467
- 'exam', 'demo', 'next', 'prev', 'logout', 'ctf4ai',
479
+ 'exam', 'demo', 'nations', 'next', 'prev', 'logout', 'ctf4ai',
468
480
  ];
469
481
  if (!knownCommands.includes(cmd)) {
470
482
  // Block dangerous commands
@@ -602,6 +614,7 @@ function mapCommand(input) {
602
614
  const rest = parts.slice(1);
603
615
  const ctfShortcuts = {
604
616
  'demo': ['exam', 'demo'],
617
+ 'nations': ['exam', 'nations'],
605
618
  'next': ['exam', 'next'],
606
619
  'prev': ['exam', 'prev'],
607
620
  'logout': ['ctf', 'logout'],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.15.0",
3
+ "version": "2.15.2",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {