icoa-cli 2.19.46 → 2.19.48
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/ai4ctf.js +8 -1
- package/dist/commands/ctf4ai-demo.js +1 -1
- package/dist/lib/i18n.d.ts +6 -0
- package/dist/lib/i18n.js +7 -0
- package/dist/repl.js +63 -13
- package/package.json +1 -1
package/dist/commands/ai4ctf.js
CHANGED
|
@@ -235,7 +235,14 @@ export async function handleChatMessage(input) {
|
|
|
235
235
|
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (gemma-4-31b-it)`));
|
|
236
236
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
237
237
|
console.log();
|
|
238
|
-
|
|
238
|
+
// Prominent transition to CTF4AI — same style as exam → ai4ctf handoff.
|
|
239
|
+
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
240
|
+
console.log(chalk.white(` ${t('ai4ctfExitNextTitle')} `) + chalk.bold.red('ctf4ai') + chalk.white(` — ${t('ai4ctfExitNextSub')}`));
|
|
241
|
+
console.log(chalk.gray(` ${t('ai4ctfExitNextBody')}`));
|
|
242
|
+
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
243
|
+
console.log();
|
|
244
|
+
console.log(chalk.bold.red(' ctf4ai') + chalk.gray(` ${t('ai4ctfExitCmdNext')}`));
|
|
245
|
+
console.log(chalk.white(' back') + chalk.gray(` ${t('ai4ctfExitCmdBack')}`));
|
|
239
246
|
console.log();
|
|
240
247
|
return 'exit';
|
|
241
248
|
}
|
|
@@ -61,9 +61,9 @@ function printDemoReport(ctf4aiSolved, ctf4aiTokens) {
|
|
|
61
61
|
const tmpl = n === 1 ? t('reportRetryWrongN') : t('reportRetryWrongNPlural');
|
|
62
62
|
console.log(chalk.cyan(' retry') + chalk.gray(` ${tmpl.replace('{n}', String(n))}`));
|
|
63
63
|
}
|
|
64
|
+
console.log(chalk.cyan(' exam setup') + chalk.gray(` ${t('reportExamSetupHint')}`));
|
|
64
65
|
console.log(chalk.white(' back') + chalk.gray(` ${t('reportBackHint')}`));
|
|
65
66
|
console.log(chalk.white(' demo') + chalk.gray(` ${t('reportDemo')}`));
|
|
66
|
-
console.log(chalk.white(' nations') + chalk.gray(` ${t('reportNations')}`));
|
|
67
67
|
console.log(chalk.white(' about') + chalk.gray(` ${t('reportAboutHint')}`));
|
|
68
68
|
console.log();
|
|
69
69
|
console.log(chalk.yellow(' ICOA 2026 · Sydney, Australia · Jun 27 - Jul 2'));
|
package/dist/lib/i18n.d.ts
CHANGED
|
@@ -147,6 +147,12 @@ export declare const EN: {
|
|
|
147
147
|
reportRetryWrongNPlural: string;
|
|
148
148
|
reportBackHint: string;
|
|
149
149
|
reportAboutHint: string;
|
|
150
|
+
reportExamSetupHint: string;
|
|
151
|
+
ai4ctfExitNextTitle: string;
|
|
152
|
+
ai4ctfExitNextSub: string;
|
|
153
|
+
ai4ctfExitNextBody: string;
|
|
154
|
+
ai4ctfExitCmdNext: string;
|
|
155
|
+
ai4ctfExitCmdBack: string;
|
|
150
156
|
ai4ctfWelcomeCta: string;
|
|
151
157
|
ai4ctfHintNudge: string;
|
|
152
158
|
ai4ctfHintTechnique: string;
|
package/dist/lib/i18n.js
CHANGED
|
@@ -163,6 +163,13 @@ export const EN = {
|
|
|
163
163
|
reportRetryWrongNPlural: 'retry the {n} wrong questions',
|
|
164
164
|
reportBackHint: 'return to main menu',
|
|
165
165
|
reportAboutHint: 'Learn more about ICOA 2026',
|
|
166
|
+
reportExamSetupHint: 'next level: prepare tools for national selection',
|
|
167
|
+
// AI4CTF exit → CTF4AI transition (v2.19.47)
|
|
168
|
+
ai4ctfExitNextTitle: 'Next:',
|
|
169
|
+
ai4ctfExitNextSub: 'Challenge the AI (Prompt Injection)',
|
|
170
|
+
ai4ctfExitNextBody: 'Can you make an AI violate its own safety rules?',
|
|
171
|
+
ai4ctfExitCmdNext: 'start the next challenge',
|
|
172
|
+
ai4ctfExitCmdBack: 'return to main menu',
|
|
166
173
|
// ai4ctf welcome / CTA (v2.19.30–32)
|
|
167
174
|
ai4ctfWelcomeCta: '👉 New here? Start with the hints in order:',
|
|
168
175
|
ai4ctfHintNudge: 'nudge',
|
package/dist/repl.js
CHANGED
|
@@ -7,6 +7,9 @@ import { setReplMode } from './lib/ui.js';
|
|
|
7
7
|
import { isChatActive, handleChatMessage } from './commands/ai4ctf.js';
|
|
8
8
|
import { isCtf4aiActive, handleCtf4aiMessage } from './commands/ctf4ai-demo.js';
|
|
9
9
|
import { getExamState } from './lib/exam-state.js';
|
|
10
|
+
import { getDemoStats } from './lib/demo-stats.js';
|
|
11
|
+
import { isExamSetupComplete } from './lib/exam-setup.js';
|
|
12
|
+
import { DEMO_PICK_SIZE, DEMO_POOL_SIZE } from './lib/demo-exam.js';
|
|
10
13
|
import { resetTerminalTheme } from './lib/theme.js';
|
|
11
14
|
import { ensureSandbox, runInSandbox, isDockerAvailable } from './lib/sandbox.js';
|
|
12
15
|
import { logCommand } from './lib/logger.js';
|
|
@@ -32,6 +35,57 @@ const BLOCKED_COMMANDS = new Set([
|
|
|
32
35
|
]);
|
|
33
36
|
const INTERCEPT = '__REPL_NO_EXIT__';
|
|
34
37
|
const VERSION = '2.5.1';
|
|
38
|
+
// National Selection main menu — shown on REPL entry and when user types `back`
|
|
39
|
+
// after finishing the demo flow. Progressive onboarding per spec
|
|
40
|
+
// docs/superpowers/specs/2026-04-13-exam-national-selection-design.md §4.1:
|
|
41
|
+
// State 0 (no demo yet): recommend demo, hide exam setup / exam <token>
|
|
42
|
+
// State 1 (demo done, no setup): show demo completion + setup CTA, hide token
|
|
43
|
+
// State 2 (demo done + setup done): show token entry CTA
|
|
44
|
+
function printSelectionMenu() {
|
|
45
|
+
const stats = getDemoStats();
|
|
46
|
+
const setupDone = isExamSetupComplete();
|
|
47
|
+
const demoLine = `Free practice — ${DEMO_PICK_SIZE} questions (from pool of ${DEMO_POOL_SIZE})`;
|
|
48
|
+
console.log();
|
|
49
|
+
console.log(' ' + chalk.cyan.bold('[Selection Mode]'));
|
|
50
|
+
console.log();
|
|
51
|
+
if (stats.attempts === 0) {
|
|
52
|
+
// State 0: brand new user. Only demo matters right now.
|
|
53
|
+
console.log(chalk.white(' New here? Start with ') + chalk.bold.cyan('demo') + chalk.white(' — it takes a few minutes.'));
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
56
|
+
console.log(chalk.bold.cyan(' demo') + chalk.gray(` ${demoLine}`));
|
|
57
|
+
console.log(chalk.white(' lang es') + chalk.gray(' Switch language (17 supported)'));
|
|
58
|
+
console.log(chalk.gray(' e.g. lang es (Español), lang zh, lang fr'));
|
|
59
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
60
|
+
}
|
|
61
|
+
else if (!setupDone) {
|
|
62
|
+
// State 1: demo done at least once, but exam environment not installed.
|
|
63
|
+
const plural = stats.attempts === 1 ? 'attempt' : 'attempts';
|
|
64
|
+
console.log(chalk.green(' ✓ Demo completed ') + chalk.gray(`(${stats.attempts} ${plural}${stats.bestPercentage > 0 ? ` · best ${stats.bestPercentage}%` : ''})`));
|
|
65
|
+
console.log(chalk.yellow(' → Next: prepare your environment for the real exam.'));
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
68
|
+
console.log(chalk.white(' demo') + chalk.gray(` ${demoLine}`));
|
|
69
|
+
console.log(chalk.bold.yellow(' exam setup') + chalk.gray(' Install tools for national selection (~150MB)'));
|
|
70
|
+
console.log(chalk.white(' lang es') + chalk.gray(' Switch language (17 supported)'));
|
|
71
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// State 2: fully prepared. Show the token entry CTA.
|
|
75
|
+
const plural = stats.attempts === 1 ? 'attempt' : 'attempts';
|
|
76
|
+
console.log(chalk.green(' ✓ Demo completed ') + chalk.gray(`(${stats.attempts} ${plural})`));
|
|
77
|
+
console.log(chalk.green(' ✓ Environment ready'));
|
|
78
|
+
console.log(chalk.yellow(' → Enter your exam token to begin.'));
|
|
79
|
+
console.log();
|
|
80
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
81
|
+
console.log(chalk.white(' demo') + chalk.gray(` ${demoLine}`));
|
|
82
|
+
console.log(chalk.bold.yellow(' exam <token>') + chalk.gray(' Enter exam with access token'));
|
|
83
|
+
console.log(chalk.white(' exam setup') + chalk.gray(' Re-verify tool environment'));
|
|
84
|
+
console.log(chalk.white(' lang es') + chalk.gray(' Switch language (17 supported)'));
|
|
85
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
86
|
+
}
|
|
87
|
+
console.log();
|
|
88
|
+
}
|
|
35
89
|
export async function startRepl(program, resumeMode) {
|
|
36
90
|
const config = getConfig();
|
|
37
91
|
const connected = isConnected();
|
|
@@ -173,18 +227,7 @@ export async function startRepl(program, resumeMode) {
|
|
|
173
227
|
}
|
|
174
228
|
// ─── Mode-specific welcome ───
|
|
175
229
|
if (mode === 'selection') {
|
|
176
|
-
|
|
177
|
-
console.log(' ' + modeLabel);
|
|
178
|
-
console.log();
|
|
179
|
-
console.log(chalk.white(' Ready to start? Just type ') + chalk.bold.cyan('demo') + chalk.white(' and press ') + chalk.yellow('Enter') + chalk.white('!'));
|
|
180
|
-
console.log();
|
|
181
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
182
|
-
console.log(chalk.bold.cyan(' demo') + chalk.gray(' Free practice exam (15 questions)'));
|
|
183
|
-
console.log(chalk.white(' exam <token>') + chalk.gray(' Enter exam with access token'));
|
|
184
|
-
console.log(chalk.white(' lang es') + chalk.gray(' Switch language (15 supported)'));
|
|
185
|
-
console.log(chalk.gray(' e.g. lang es (Español), lang zh, lang fr'));
|
|
186
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
187
|
-
console.log();
|
|
230
|
+
printSelectionMenu();
|
|
188
231
|
}
|
|
189
232
|
else if (mode === 'organizer') {
|
|
190
233
|
console.log(chalk.yellow.bold(' [National/Regional Partner]'));
|
|
@@ -374,7 +417,14 @@ export async function startRepl(program, resumeMode) {
|
|
|
374
417
|
}),
|
|
375
418
|
signal: AbortSignal.timeout(5000),
|
|
376
419
|
}).catch(() => { });
|
|
377
|
-
|
|
420
|
+
// Show the National Selection menu so the user always knows what
|
|
421
|
+
// commands are available (demo / exam setup / exam <token>).
|
|
422
|
+
if (mode === 'selection') {
|
|
423
|
+
printSelectionMenu();
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
console.log(chalk.gray(' Already at main menu.'));
|
|
427
|
+
}
|
|
378
428
|
}
|
|
379
429
|
rl.prompt();
|
|
380
430
|
return;
|