icoa-cli 2.15.1 → 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 +36 -0
- 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]')
|
|
@@ -638,6 +670,10 @@ export function registerExamCommand(program) {
|
|
|
638
670
|
console.log(chalk.green.bold(' ai4ctf') + chalk.gray(' Chat with AI teammate (start here!)'));
|
|
639
671
|
console.log(chalk.red.bold(' ctf4ai') + chalk.gray(' Trick the AI — make it say "koala"'));
|
|
640
672
|
console.log();
|
|
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'));
|
|
676
|
+
console.log();
|
|
641
677
|
}
|
|
642
678
|
catch (err) {
|
|
643
679
|
console.log();
|
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'],
|