icoa-cli 2.19.91 → 2.19.93

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/index.js CHANGED
@@ -15,7 +15,6 @@ import { registerEnvCommand } from './commands/env.js';
15
15
  import { registerAi4ctfCommand } from './commands/ai4ctf.js';
16
16
  import { registerExamCommand } from './commands/exam.js';
17
17
  import { registerCtf4aiDemoCommand } from './commands/ctf4ai-demo.js';
18
- import { registerTutorialCommand } from './commands/tutorial.js';
19
18
  import { registerThemeCommand } from './commands/theme.js';
20
19
  import { getConfig, saveConfig } from './lib/config.js';
21
20
  import { startRepl } from './repl.js';
@@ -149,7 +148,6 @@ registerEnvCommand(program);
149
148
  registerAi4ctfCommand(program);
150
149
  registerExamCommand(program);
151
150
  registerCtf4aiDemoCommand(program);
152
- registerTutorialCommand(program);
153
151
  registerThemeCommand(program);
154
152
  // Hidden command: switch AI model
155
153
  program
package/dist/repl.js CHANGED
@@ -162,8 +162,8 @@ function printSelectionMenu() {
162
162
  console.log();
163
163
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
164
164
  console.log(chalk.bold.cyan(' demo') + chalk.gray(` ${demoLine}`));
165
- console.log(chalk.white(' lang es') + chalk.gray(' Switch language (17 supported)'));
166
- console.log(chalk.gray(' e.g. lang es (Español), lang zh, lang fr'));
165
+ console.log(chalk.white(' lang') + chalk.gray(' List all supported languages'));
166
+ console.log(chalk.white(' lang es') + chalk.gray(' Switch language (e.g. lang es, lang zh, lang fr)'));
167
167
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
168
168
  }
169
169
  else if (!setupDone) {
@@ -175,7 +175,8 @@ function printSelectionMenu() {
175
175
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
176
176
  console.log(chalk.white(' demo') + chalk.gray(` ${demoLine}`));
177
177
  console.log(chalk.bold.yellow(' exam setup') + chalk.gray(' Install tools for national selection (~150MB)'));
178
- console.log(chalk.white(' lang es') + chalk.gray(' Switch language (17 supported)'));
178
+ console.log(chalk.white(' lang') + chalk.gray(' List all supported languages'));
179
+ console.log(chalk.white(' lang es') + chalk.gray(' Switch language (e.g. lang es, lang zh, lang fr)'));
179
180
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
180
181
  }
181
182
  else {
@@ -196,15 +197,12 @@ function printSelectionMenu() {
196
197
  console.log(chalk.gray(' Other commands:'));
197
198
  console.log(chalk.white(' demo') + chalk.gray(` ${demoLine}`));
198
199
  console.log(chalk.white(' exam setup') + chalk.gray(' Re-verify tool environment'));
199
- console.log(chalk.white(' lang es') + chalk.gray(' Switch language (17 supported)'));
200
+ console.log(chalk.white(' lang') + chalk.gray(' List all supported languages'));
201
+ console.log(chalk.white(' lang es') + chalk.gray(' Switch language (e.g. lang es, lang zh, lang fr)'));
200
202
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
201
203
  }
202
- // Beginner-friendly safety net: make it obvious how to pause / exit / get help.
203
- // This is the first place a new K-12 user lands, so the three escape hatches
204
- // need to be visible without cluttering the main command list above.
205
204
  console.log(chalk.gray(' ') +
206
205
  chalk.gray('Tip: ') + chalk.cyan('help') + chalk.gray(' for commands · ') +
207
- chalk.cyan('tutorial') + chalk.gray(' for 30-sec walkthrough · ') +
208
206
  chalk.cyan('Ctrl+C') + chalk.gray(' pauses · ') +
209
207
  chalk.cyan('quit') + chalk.gray(' closes'));
210
208
  console.log();
@@ -234,12 +232,10 @@ export async function startRepl(program, resumeMode) {
234
232
  // ─── Mode selection (every launch) ───
235
233
  const { select: selectMode, confirm: confirmMode } = await import('@inquirer/prompts');
236
234
  const savedMode = config.mode || '';
237
- // T3-10: Mode labels clarified for K-12 newcomers who don't know the
238
- // difference between "selection" and "olympiad" at first glance.
239
235
  const modeChoices = [
240
- { name: ` ${chalk.bold('National Selection')} ${chalk.gray('·')} ${chalk.green('K-12 recommended')} ${chalk.gray('demo, exam, lightweight')}`, value: 'selection' },
241
- { name: ` ${chalk.bold('International Olympiad')} ${chalk.gray('·')} ${chalk.yellow('Advanced')} ${chalk.gray('CTF x AI (~500MB)')}`, value: 'olympiad' },
242
- { name: ` ${chalk.bold('National/Regional Partner')} ${chalk.gray('·')} ${chalk.cyan('Organizers')} ${chalk.gray(' token & competition mgmt')}`, value: 'organizer' },
236
+ { name: ` ${chalk.bold('National Selection')} ${chalk.gray('')} ${chalk.gray('demo, exam (lightweight)')}`, value: 'selection' },
237
+ { name: ` ${chalk.bold('International Olympiad')} ${chalk.gray('')} ${chalk.gray('CTF × AI (~500MB, advanced)')}`, value: 'olympiad' },
238
+ { name: ` ${chalk.bold('National/Regional Partner')} ${chalk.gray('')} ${chalk.gray('organizer tools (tokens, competitions)')}`, value: 'organizer' },
243
239
  { name: ` ${chalk.gray('About ICOA')} ${chalk.gray('·')} ${chalk.gray('Info & contact')}`, value: 'about' },
244
240
  ];
245
241
  console.log(chalk.gray(' Use ') + chalk.yellow('↑') + chalk.gray(' or ') + chalk.yellow('↓') + chalk.gray(' to select, ') + chalk.yellow('Enter') + chalk.gray(' to confirm.'));
@@ -433,9 +429,7 @@ export async function startRepl(program, resumeMode) {
433
429
  console.log(chalk.white(' scoreboard') + chalk.gray(' Live rankings'));
434
430
  console.log(chalk.white(' help') + chalk.gray(' Full command list'));
435
431
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
436
- // T4-X1: parity with Selection-mode footer give Olympiad users the
437
- // same beginner escape-hatch hint so newcomers don't get stuck.
438
- console.log(chalk.gray(' Tip: ') + chalk.cyan('help') + chalk.gray(' · ') + chalk.cyan('tutorial') + chalk.gray(' 30-sec tour · ') + chalk.cyan('Ctrl+C') + chalk.gray(' pauses · ') + chalk.cyan('quit') + chalk.gray(' closes'));
432
+ console.log(chalk.gray(' Tip: ') + chalk.cyan('help') + chalk.gray(' · ') + chalk.cyan('Ctrl+C') + chalk.gray(' pauses · ') + chalk.cyan('quit') + chalk.gray(' closes'));
439
433
  console.log();
440
434
  }
441
435
  else if (activated) {
@@ -450,7 +444,7 @@ export async function startRepl(program, resumeMode) {
450
444
  console.log(chalk.white(' Step 2 ') + chalk.bold.cyan('challenges') + chalk.gray(' Browse & solve challenges'));
451
445
  console.log(chalk.white(' Step 3 ') + chalk.bold.cyan('hint') + chalk.gray(' Ask AI when stuck'));
452
446
  console.log();
453
- console.log(chalk.gray(' Also: ') + chalk.white('env') + chalk.gray(' check tools ') + chalk.white('help') + chalk.gray(' all commands ') + chalk.white('tutorial') + chalk.gray(' 30-sec tour'));
447
+ console.log(chalk.gray(' Also: ') + chalk.white('env') + chalk.gray(' check tools ') + chalk.white('help') + chalk.gray(' all commands'));
454
448
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
455
449
  console.log(chalk.gray(' Tip: ') + chalk.cyan('Ctrl+C') + chalk.gray(' pauses · ') + chalk.cyan('exit') + chalk.gray(' → menu · ') + chalk.cyan('quit') + chalk.gray(' closes CLI'));
456
450
  console.log();
@@ -468,7 +462,6 @@ export async function startRepl(program, resumeMode) {
468
462
  console.log(chalk.white(' ref web') + chalk.gray(' Quick reference for Web'));
469
463
  console.log(chalk.white(' env') + chalk.gray(' Check your tools'));
470
464
  console.log(chalk.white(' help') + chalk.gray(' All available commands'));
471
- console.log(chalk.white(' tutorial') + chalk.gray(' 30-second walkthrough for first-timers'));
472
465
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
473
466
  console.log(chalk.gray(' Tip: ') + chalk.cyan('Ctrl+C') + chalk.gray(' pauses · ') + chalk.cyan('exit') + chalk.gray(' → menu · ') + chalk.cyan('quit') + chalk.gray(' closes CLI'));
474
467
  console.log();
@@ -991,7 +984,7 @@ export async function startRepl(program, resumeMode) {
991
984
  const KNOWN_CMDS = [
992
985
  'ctf', 'hint', 'hint-b', 'hint-c', 'hint-budget', 'ref', 'shell',
993
986
  'files', 'connect', 'note', 'log', 'lang', 'setup', 'env',
994
- 'ai4ctf', 'exam', 'ctf4ai', 'tutorial', 'theme',
987
+ 'ai4ctf', 'exam', 'ctf4ai', 'theme',
995
988
  'clear', 'cls', 'quit', 'exit', 'back', 'menu', 'help',
996
989
  'continue', 'activate', 'demo', 'challenges', 'status', 'scoreboard',
997
990
  'join', 'logout',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.91",
3
+ "version": "2.19.93",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,12 +0,0 @@
1
- /**
2
- * `tutorial` command — a 30-second interactive walk-through for K-12 beginners
3
- * who have never used a command-line tool before. Explains the 4 core
4
- * mechanics of ICOA CLI: typing commands, answering questions, getting help,
5
- * and exiting safely. No real exam state touched — pure narration + press-Enter.
6
- *
7
- * Triggered by: typing `tutorial` at the REPL prompt.
8
- * Advertised in: printSelectionMenu tip footer and help listings.
9
- */
10
- import { Command } from 'commander';
11
- export declare function runTutorial(): Promise<void>;
12
- export declare function registerTutorialCommand(program: Command): void;
@@ -1,127 +0,0 @@
1
- /**
2
- * `tutorial` command — a 30-second interactive walk-through for K-12 beginners
3
- * who have never used a command-line tool before. Explains the 4 core
4
- * mechanics of ICOA CLI: typing commands, answering questions, getting help,
5
- * and exiting safely. No real exam state touched — pure narration + press-Enter.
6
- *
7
- * Triggered by: typing `tutorial` at the REPL prompt.
8
- * Advertised in: printSelectionMenu tip footer and help listings.
9
- */
10
- import chalk from 'chalk';
11
- function waitForEnter(promptText = ' Press Enter to continue... ') {
12
- // Raw-stdin read (matches pattern used by exam start + demo confirm).
13
- // A second readline on process.stdin fights the parent REPL, so we read
14
- // raw bytes and resolve on \n or \r.
15
- return new Promise((resolve) => {
16
- process.stdout.write(chalk.bold.yellow(promptText));
17
- const wasRaw = process.stdin.isTTY ? process.stdin.isRaw : false;
18
- if (process.stdin.isTTY && process.stdin.setRawMode) {
19
- process.stdin.setRawMode(false);
20
- }
21
- const onData = (chunk) => {
22
- const s = chunk.toString();
23
- if (s.includes('\n') || s.includes('\r')) {
24
- process.stdin.removeListener('data', onData);
25
- if (process.stdin.isTTY && process.stdin.setRawMode) {
26
- process.stdin.setRawMode(wasRaw);
27
- }
28
- process.stdout.write('\n');
29
- resolve();
30
- }
31
- };
32
- process.stdin.on('data', onData);
33
- process.stdin.resume();
34
- });
35
- }
36
- function divider() {
37
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
38
- }
39
- function screenHeader(n, total, title) {
40
- console.log();
41
- console.log(chalk.cyan(` ─── Step ${n} / ${total} · ${title} ───`));
42
- console.log();
43
- }
44
- export async function runTutorial() {
45
- console.log();
46
- console.log(chalk.bold.green(' 📚 ICOA CLI — 30-Second Tutorial'));
47
- console.log(chalk.gray(' Never used a command-line before? You\'ll be fine. 4 steps total.'));
48
- console.log();
49
- await waitForEnter();
50
- // ─── Step 1 ───────────────────────────────────────────────────────
51
- screenHeader(1, 4, 'Typing commands');
52
- console.log(chalk.white(' The CLI waits for you to ') + chalk.bold('type a command and press Enter') + chalk.white('.'));
53
- console.log();
54
- console.log(chalk.gray(' For example, when you see the prompt:'));
55
- console.log();
56
- console.log(' ' + chalk.cyan('icoa> '));
57
- console.log();
58
- console.log(chalk.gray(' You type a word like ') + chalk.cyan('help') + chalk.gray(' or ') + chalk.cyan('demo') + chalk.gray(' and press Enter.'));
59
- console.log(chalk.gray(' If you type something wrong, nothing bad happens — try again.'));
60
- console.log();
61
- await waitForEnter();
62
- // ─── Step 2 ───────────────────────────────────────────────────────
63
- screenHeader(2, 4, 'Answering questions');
64
- console.log(chalk.white(' Multiple-choice questions show 4 options (A / B / C / D).'));
65
- console.log(chalk.gray(' Example:'));
66
- console.log();
67
- divider();
68
- console.log(chalk.white(' Q1. Which command shows the current directory?'));
69
- console.log(chalk.gray(' A) cd B) pwd C) ls D) dir'));
70
- divider();
71
- console.log();
72
- console.log(chalk.gray(' To answer, type: ') + chalk.cyan('exam answer 1 B') + chalk.gray(' (question number + letter)'));
73
- console.log(chalk.gray(' Or the shortcut: ') + chalk.cyan('B') + chalk.gray(' (letter alone on the current question)'));
74
- console.log();
75
- console.log(chalk.gray(' After you answer, the CLI auto-saves — you won\'t lose work if you exit.'));
76
- console.log();
77
- await waitForEnter();
78
- // ─── Step 3 ───────────────────────────────────────────────────────
79
- screenHeader(3, 4, 'Getting help when stuck');
80
- console.log(chalk.white(' Stuck? Several ways to get help, from gentlest to most revealing:'));
81
- console.log();
82
- console.log(' ' + chalk.cyan('help') + chalk.gray(' — list all available commands'));
83
- console.log(' ' + chalk.cyan('help ') + chalk.gray('(or ') + chalk.cyan('?') + chalk.gray(') — same, shorter to type'));
84
- console.log(' ' + chalk.cyan('ref grep') + chalk.gray(' — quick reference for a specific tool'));
85
- console.log();
86
- console.log(chalk.white(' Inside a question:'));
87
- console.log(' ' + chalk.cyan('help') + chalk.gray(' — eliminate one wrong multiple-choice option'));
88
- console.log(' ' + chalk.cyan('hint a') + chalk.gray(' — general direction (practical questions only)'));
89
- console.log(' ' + chalk.cyan('hint b') + chalk.gray(' — specific technique'));
90
- console.log(' ' + chalk.cyan('hint c') + chalk.gray(' — near-solution (masked, 50% revealed)'));
91
- console.log();
92
- console.log(chalk.gray(' The exam has a budget for each — using one doesn\'t end the question.'));
93
- console.log();
94
- await waitForEnter();
95
- // ─── Step 4 ───────────────────────────────────────────────────────
96
- screenHeader(4, 4, 'Exiting & pausing safely');
97
- console.log(chalk.white(' Three escape hatches, each with a different meaning:'));
98
- console.log();
99
- console.log(' ' + chalk.cyan('back') + chalk.gray(' or ') + chalk.cyan('menu') + chalk.gray(' — return to the main menu; exam stays saved, timer keeps running'));
100
- console.log(' ' + chalk.cyan('exit') + chalk.gray(' — same as back (from any prompt)'));
101
- console.log(' ' + chalk.cyan('quit') + chalk.gray(' — close the CLI entirely; next time use ') + chalk.cyan('icoa --resume'));
102
- console.log(' ' + chalk.cyan('Ctrl+C') + chalk.gray(' — pause + show where you are (no data loss)'));
103
- console.log();
104
- console.log(chalk.gray(' Closing your terminal window is also safe — your answers are on disk.'));
105
- console.log();
106
- await waitForEnter();
107
- // ─── Final ────────────────────────────────────────────────────────
108
- console.log();
109
- console.log(chalk.bold.green(' ✨ That\'s it. You\'re ready.'));
110
- console.log();
111
- console.log(chalk.white(' Try next:'));
112
- console.log(' ' + chalk.cyan('demo') + chalk.gray(' — free practice (10 questions, no timer)'));
113
- console.log(' ' + chalk.cyan('exam <token>') + chalk.gray(' — real exam (when you have an organizer-issued token)'));
114
- console.log(' ' + chalk.cyan('lang es') + chalk.gray(' — switch UI language (17 supported)'));
115
- console.log(' ' + chalk.cyan('theme high-contrast') + chalk.gray(' — low-vision-friendly colors (restart after)'));
116
- console.log();
117
- console.log(chalk.gray(' Full beginner guide: ') + chalk.cyan.underline('https://github.com/newaipanda/ICOA_CLI/blob/main/docs/getting-started-k12.md'));
118
- console.log();
119
- }
120
- export function registerTutorialCommand(program) {
121
- program
122
- .command('tutorial')
123
- .description('30-second walk-through for first-time CLI users')
124
- .action(async () => {
125
- await runTutorial();
126
- });
127
- }