icoa-cli 2.19.56 → 2.19.57

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.
@@ -335,8 +335,76 @@ function getHelpState(state) {
335
335
  eliminated: state._eliminated || {},
336
336
  };
337
337
  }
338
- // Track whether the practical section intro has been shown this session
339
- let _practicalIntroShown = false;
338
+ // Section intros fire once per REPL session, first time the user enters
339
+ // that section. State-persisted via shownWarnings keys 's_ai4ctf' / 's_ctf4ai'
340
+ // so jumping back and forth doesn't re-fire them.
341
+ function printSectionIntro(state, currentQ) {
342
+ if (state.session.examId === 'demo-free')
343
+ return;
344
+ const total = Number(state.session.questionCount || 40);
345
+ // Only 40-question exams have the three-section structure
346
+ if (total < 40)
347
+ return;
348
+ const shown = new Set(state.shownWarnings || []);
349
+ // ─── AI4CTF section intro (Q31 = first practical, AI-as-teammate) ───
350
+ if (currentQ >= 31 && currentQ <= 38 && !shown.has('s_ai4ctf')) {
351
+ console.log();
352
+ console.log(chalk.green(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
353
+ console.log(chalk.bold.green(' 🚀 Section 2: AI4CTF — AI is your teammate'));
354
+ console.log(chalk.green(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
355
+ console.log();
356
+ console.log(chalk.white(' Welcome to the practical CTF section. Real'));
357
+ console.log(chalk.white(' security tasks — crypto, web, forensics, pwn.'));
358
+ console.log();
359
+ console.log(chalk.bold.white(' Q31–38 (8 questions · 6 pts each)'));
360
+ console.log(chalk.gray(' Solve ') + chalk.bold('with') + chalk.gray(' AI by your side. AI is your teammate.'));
361
+ console.log();
362
+ console.log(chalk.bold.white(' How to work'));
363
+ console.log(chalk.gray(' Run Python: ') + chalk.green('!python3 -c "print(1+1)"'));
364
+ console.log(chalk.gray(' ') + chalk.green('!python3') + chalk.gray(' for REPL'));
365
+ console.log(chalk.gray(' Ask AI: ') + chalk.bold.cyan('hint') + chalk.gray(' — free-form question'));
366
+ console.log(chalk.gray(' Submit flag: ') + chalk.green('exam answer <n> ICOA{...}'));
367
+ console.log();
368
+ console.log(chalk.bold.white(' Budget'));
369
+ console.log(chalk.gray(' AI tokens: ') + chalk.white('25,000') + chalk.gray(' for this section'));
370
+ console.log(chalk.gray(' Hints A/B/C: ') + chalk.white('5 / 3 / 1') + chalk.gray(' structured hints per question'));
371
+ console.log();
372
+ console.log(chalk.yellow(' Time still counting down. Budget ~2 min per question.'));
373
+ console.log(chalk.green(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
374
+ console.log();
375
+ shown.add('s_ai4ctf');
376
+ state.shownWarnings = Array.from(shown);
377
+ saveExamState(state);
378
+ return;
379
+ }
380
+ // ─── CTF4AI section intro (Q39 = adversarial AI, highest-value questions) ───
381
+ if (currentQ >= 39 && !shown.has('s_ctf4ai')) {
382
+ console.log();
383
+ console.log(chalk.red(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
384
+ console.log(chalk.bold.red(' 🎯 Section 3: CTF4AI — Challenge the AI'));
385
+ console.log(chalk.red(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
386
+ console.log();
387
+ console.log(chalk.white(' The final section flips the script: instead of'));
388
+ console.log(chalk.white(' using AI, you\'re ') + chalk.bold('attacking') + chalk.white(' AI systems.'));
389
+ console.log();
390
+ console.log(chalk.bold.white(' Q39–40 (2 questions · 16 pts each — highest value!)'));
391
+ console.log(chalk.gray(' Prompt injection · adversarial analysis · AI auditing'));
392
+ console.log();
393
+ console.log(chalk.bold.white(' How this differs from AI4CTF'));
394
+ console.log(chalk.gray(' · AI is your ') + chalk.red('target') + chalk.gray(', not your teammate'));
395
+ console.log(chalk.gray(' · Read the scenario carefully — rules vary'));
396
+ console.log(chalk.gray(' · Separate AI budget: ') + chalk.white('25,000 tokens'));
397
+ console.log();
398
+ console.log(chalk.yellow(' These are the hardest questions. Worth 21% of total score.'));
399
+ console.log(chalk.yellow(' If time is tight, skim Q39/40 first to decide attack order.'));
400
+ console.log(chalk.red(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
401
+ console.log();
402
+ shown.add('s_ctf4ai');
403
+ state.shownWarnings = Array.from(shown);
404
+ saveExamState(state);
405
+ return;
406
+ }
407
+ }
340
408
  function printQuestion(q, answer) {
341
409
  const state = getExamState();
342
410
  const total = Number(state?.session.questionCount || 30);
@@ -347,25 +415,9 @@ function printQuestion(q, answer) {
347
415
  // Pacing hints (Q10 time check, Q30 section complete) — real exam only
348
416
  if (state)
349
417
  printPacingHint(state, q.number);
350
- // Show practical section intro once when first entering Q31+
351
- if (isPractical && !_practicalIntroShown && state?.session.examId !== 'demo-free') {
352
- _practicalIntroShown = true;
353
- console.log();
354
- console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
355
- console.log(chalk.bold.white(' Practical Section — Python Required'));
356
- console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
357
- console.log();
358
- console.log(chalk.white(' Three ways to run Python:'));
359
- console.log();
360
- console.log(chalk.yellow(' 1.') + chalk.white(' One-liner: ') + chalk.green('!python3 -c "print(1+1)"'));
361
- console.log(chalk.yellow(' 2.') + chalk.white(' Interactive: ') + chalk.green('!python3') + chalk.gray(' → >>> import struct ...'));
362
- console.log(chalk.yellow(' 3.') + chalk.white(' Script: ') + chalk.green("!cat << 'EOF' > s.py") + chalk.gray(' → ') + chalk.green('!python3 s.py'));
363
- console.log();
364
- console.log(chalk.white(' Need help? Type ') + chalk.bold.cyan('hint') + chalk.white(' to ask AI (25K tokens per section)'));
365
- console.log(chalk.white(' Submit flag: ') + chalk.green('exam answer <n> ICOA{your_flag}'));
366
- console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
367
- console.log();
368
- }
418
+ // Section intros (AI4CTF at Q31, CTF4AI at Q39) — real exam only
419
+ if (state && isPractical)
420
+ printSectionIntro(state, q.number);
369
421
  // Urgent countdown warnings (10 / 5 / 1 minutes remaining)
370
422
  if (state)
371
423
  printTimeWarningIfNeeded(state);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.56",
3
+ "version": "2.19.57",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {