icoa-cli 2.7.1 → 2.8.0
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 +10 -10
- package/dist/repl.js +32 -0
- package/package.json +1 -1
package/dist/commands/exam.js
CHANGED
|
@@ -85,13 +85,9 @@ function printQuestion(q, answer) {
|
|
|
85
85
|
}
|
|
86
86
|
console.log();
|
|
87
87
|
// Navigation hint
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (q.number < total)
|
|
92
|
-
nav.push('exam next');
|
|
93
|
-
nav.push(`exam answer ${q.number} <A-D>`);
|
|
94
|
-
console.log(chalk.gray(` ${nav.join(' · ')}`));
|
|
88
|
+
console.log(chalk.gray(' Type ') + chalk.white('A') + chalk.gray('/') + chalk.white('B') + chalk.gray('/') + chalk.white('C') + chalk.gray('/') + chalk.white('D') + chalk.gray(' to answer') +
|
|
89
|
+
(q.number > 1 ? chalk.gray(' · ') + chalk.white('prev') : '') +
|
|
90
|
+
(q.number < total ? chalk.gray(' · ') + chalk.white('next') : ''));
|
|
95
91
|
}
|
|
96
92
|
export function registerExamCommand(program) {
|
|
97
93
|
const exam = program.command('exam').description('National selection exam');
|
|
@@ -153,8 +149,9 @@ export function registerExamCommand(program) {
|
|
|
153
149
|
if (!client)
|
|
154
150
|
return;
|
|
155
151
|
const proceed = await confirm({
|
|
156
|
-
message: 'Start the exam? The timer will begin immediately.',
|
|
152
|
+
message: chalk.white('Start the exam? The timer will begin immediately.'),
|
|
157
153
|
default: true,
|
|
154
|
+
theme: { prefix: '', style: { message: (t) => t, defaultAnswer: (t) => chalk.green(t) } },
|
|
158
155
|
});
|
|
159
156
|
if (!proceed)
|
|
160
157
|
return;
|
|
@@ -209,6 +206,8 @@ export function registerExamCommand(program) {
|
|
|
209
206
|
printError(`Question ${n} not found (1-${state.questions.length}).`);
|
|
210
207
|
return;
|
|
211
208
|
}
|
|
209
|
+
state._lastQ = num;
|
|
210
|
+
saveExamState(state);
|
|
212
211
|
printQuestion(q, state.answers[num]);
|
|
213
212
|
}
|
|
214
213
|
else {
|
|
@@ -369,7 +368,7 @@ export function registerExamCommand(program) {
|
|
|
369
368
|
msg += chalk.yellow(` ${unanswered} unanswered.`);
|
|
370
369
|
}
|
|
371
370
|
msg += ' This cannot be undone.';
|
|
372
|
-
const proceed = await confirm({ message: msg, default: false });
|
|
371
|
+
const proceed = await confirm({ message: chalk.white(msg), default: false, theme: { prefix: '', style: { message: (t) => t, defaultAnswer: (t) => chalk.green(t) } } });
|
|
373
372
|
if (!proceed)
|
|
374
373
|
return;
|
|
375
374
|
console.log();
|
|
@@ -511,8 +510,9 @@ export function registerExamCommand(program) {
|
|
|
511
510
|
console.log(chalk.gray(' └─────────────────────────────────────────────────┘'));
|
|
512
511
|
console.log();
|
|
513
512
|
const proceed = await confirm({
|
|
514
|
-
message: 'Start demo exam now?',
|
|
513
|
+
message: chalk.white('Start demo exam now?'),
|
|
515
514
|
default: true,
|
|
515
|
+
theme: { prefix: '', style: { message: (t) => t, defaultAnswer: (t) => chalk.green(t) } },
|
|
516
516
|
});
|
|
517
517
|
if (!proceed)
|
|
518
518
|
return;
|
package/dist/repl.js
CHANGED
|
@@ -5,6 +5,7 @@ import { isConnected, getConfig, saveConfig } from './lib/config.js';
|
|
|
5
5
|
import { isActivated, activateToken, isFreeCommand, isDeviceMatch, recordExit, recordResume, isFirstRunOrUpgrade, markVersionSeen } from './lib/access.js';
|
|
6
6
|
import { setReplMode } from './lib/ui.js';
|
|
7
7
|
import { isChatActive, handleChatMessage } from './commands/ai4ctf.js';
|
|
8
|
+
import { getExamState } from './lib/exam-state.js';
|
|
8
9
|
import { resetTerminalTheme } from './lib/theme.js';
|
|
9
10
|
import { ensureSandbox, runInSandbox, isDockerAvailable } from './lib/sandbox.js';
|
|
10
11
|
import { logCommand } from './lib/logger.js';
|
|
@@ -271,6 +272,37 @@ export async function startRepl(program, resumeMode) {
|
|
|
271
272
|
rl.prompt();
|
|
272
273
|
return;
|
|
273
274
|
}
|
|
275
|
+
// ─── Quick exam answer shortcuts ───
|
|
276
|
+
// "A" / "B" / "C" / "D" → answer current question
|
|
277
|
+
// "2 C" / "5 A" → answer specific question
|
|
278
|
+
const examState = getExamState();
|
|
279
|
+
if (examState) {
|
|
280
|
+
const upper = input.toUpperCase().trim();
|
|
281
|
+
// Single letter: A, B, C, D → answer current question
|
|
282
|
+
if (/^[ABCD]$/.test(upper)) {
|
|
283
|
+
const currentQ = examState._lastQ || 1;
|
|
284
|
+
processing = true;
|
|
285
|
+
try {
|
|
286
|
+
await program.parseAsync(['node', 'icoa', 'exam', 'answer', String(currentQ), upper]);
|
|
287
|
+
}
|
|
288
|
+
catch { }
|
|
289
|
+
processing = false;
|
|
290
|
+
rl.prompt();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// "N X" pattern: e.g. "2 C", "15 A"
|
|
294
|
+
const match = upper.match(/^(\d+)\s+([ABCD])$/);
|
|
295
|
+
if (match) {
|
|
296
|
+
processing = true;
|
|
297
|
+
try {
|
|
298
|
+
await program.parseAsync(['node', 'icoa', 'exam', 'answer', match[1], match[2]]);
|
|
299
|
+
}
|
|
300
|
+
catch { }
|
|
301
|
+
processing = false;
|
|
302
|
+
rl.prompt();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
274
306
|
const cmd = input.split(/\s+/)[0].toLowerCase();
|
|
275
307
|
// ─── Mode-based command filtering ───
|
|
276
308
|
const selectionCommands = ['join', 'exam', 'demo', 'next', 'prev', 'setup', 'lang', 'ref', 'ctf'];
|