icoa-cli 2.19.61 → 2.19.62
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 +14 -0
- package/dist/commands/ctf4ai-demo.js +11 -0
- package/package.json +1 -1
package/dist/commands/ai4ctf.js
CHANGED
|
@@ -311,8 +311,12 @@ export async function handleChatMessage(input) {
|
|
|
311
311
|
function printExamAi4ctfWelcome(q, qNum) {
|
|
312
312
|
const config = getConfig();
|
|
313
313
|
const modelName = config.geminiModel || 'gemma-4-31b-it';
|
|
314
|
+
const isResume = chatTokensUsed > 0;
|
|
314
315
|
console.log();
|
|
315
316
|
console.log(chalk.green.bold(` ═══ AI4CTF — Q${qNum}: ${q.category} ═══`));
|
|
317
|
+
if (isResume) {
|
|
318
|
+
console.log(chalk.gray(` (resuming — prior chat is not remembered, but tokens already used stay deducted)`));
|
|
319
|
+
}
|
|
316
320
|
console.log();
|
|
317
321
|
console.log(chalk.cyan(' ┌─────────────────────────────────────────────'));
|
|
318
322
|
console.log(chalk.cyan(' │ ') + chalk.bold.white(`Q${qNum} [${q.category}] · ${q.points || 6} pts`));
|
|
@@ -426,6 +430,16 @@ async function handleExamAi4ctfMessage(input) {
|
|
|
426
430
|
const submitMatch = trimmed.match(/^submit\s+(.+)/i);
|
|
427
431
|
if (submitMatch) {
|
|
428
432
|
const flag = submitMatch[1].trim();
|
|
433
|
+
// Letter-only footgun: reject 'A'/'B'/'C'/'D' as flags. Same defence we
|
|
434
|
+
// added at the REPL and exam-answer layers; duplicated here because chat
|
|
435
|
+
// bypasses both.
|
|
436
|
+
if (/^[A-Da-d]$/.test(flag)) {
|
|
437
|
+
console.log();
|
|
438
|
+
console.log(chalk.yellow(` "${flag}" looks like an MCQ letter, not a flag.`));
|
|
439
|
+
console.log(chalk.gray(' Flag format: ') + chalk.green('ICOA{your_flag}') + chalk.gray('. Try again inside this chat.'));
|
|
440
|
+
console.log();
|
|
441
|
+
return 'continue';
|
|
442
|
+
}
|
|
429
443
|
const { getExamState, saveExamState } = await import('../lib/exam-state.js');
|
|
430
444
|
const state = getExamState();
|
|
431
445
|
if (!state)
|
|
@@ -179,8 +179,12 @@ export async function handleCtf4aiMessage(input) {
|
|
|
179
179
|
function printExamCtf4aiWelcome(q, qNum) {
|
|
180
180
|
const config = getConfig();
|
|
181
181
|
const modelName = config.geminiModel || 'gemma-4-31b-it';
|
|
182
|
+
const isResume = ctf4aiTokens > 0;
|
|
182
183
|
console.log();
|
|
183
184
|
console.log(chalk.red.bold(` ═══ CTF4AI — Q${qNum}: ${q.category} (${q.points || 16} pts) ═══`));
|
|
185
|
+
if (isResume) {
|
|
186
|
+
console.log(chalk.gray(` (resuming — prior chat is not remembered, but tokens already used stay deducted)`));
|
|
187
|
+
}
|
|
184
188
|
console.log();
|
|
185
189
|
console.log(chalk.red(' ┌─────────────────────────────────────────────'));
|
|
186
190
|
console.log(chalk.red(' │ ') + chalk.bold.white(`Q${qNum} [${q.category}] · adversarial AI`));
|
|
@@ -297,6 +301,13 @@ async function handleExamCtf4aiMessage(input) {
|
|
|
297
301
|
const submitMatch = trimmed.match(/^submit\s+(.+)/i);
|
|
298
302
|
if (submitMatch) {
|
|
299
303
|
const flag = submitMatch[1].trim();
|
|
304
|
+
if (/^[A-Da-d]$/.test(flag)) {
|
|
305
|
+
console.log();
|
|
306
|
+
console.log(chalk.yellow(` "${flag}" looks like an MCQ letter, not a flag.`));
|
|
307
|
+
console.log(chalk.gray(' Flag format: ') + chalk.green('ICOA{your_flag}') + chalk.gray('. Try again.'));
|
|
308
|
+
console.log();
|
|
309
|
+
return 'continue';
|
|
310
|
+
}
|
|
300
311
|
const { getExamState, saveExamState } = await import('../lib/exam-state.js');
|
|
301
312
|
const state = getExamState();
|
|
302
313
|
if (!state)
|