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.
- package/dist/commands/exam.js +60 -11
- package/dist/repl.js +15 -2
- package/package.json +1 -1
package/dist/commands/exam.js
CHANGED
|
@@ -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!
|
|
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.
|
|
617
|
-
console.log(chalk.gray('
|
|
618
|
-
console.log(chalk.gray('
|
|
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.
|
|
621
|
-
console.log(chalk.
|
|
622
|
-
console.log(chalk.gray('
|
|
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.
|
|
625
|
-
console.log(chalk.
|
|
626
|
-
console.log(chalk.
|
|
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'],
|