icoa-cli 2.19.66 → 2.19.67
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/lib/exam-state.d.ts +2 -2
- package/dist/lib/exam-state.js +16 -24
- package/package.json +1 -1
package/dist/lib/exam-state.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ExamState } from '../types/index.js';
|
|
2
|
-
export declare function getExamState(): ExamState | null;
|
|
3
|
-
export declare function getDemoState(): ExamState | null;
|
|
4
2
|
export declare function getRealExamState(): ExamState | null;
|
|
3
|
+
export declare function getDemoState(): ExamState | null;
|
|
4
|
+
export declare function getExamState(): ExamState | null;
|
|
5
5
|
export declare function saveExamState(state: ExamState): void;
|
|
6
6
|
export declare function clearExamState(examId?: string): void;
|
|
7
7
|
export declare function isExamActive(): boolean;
|
package/dist/lib/exam-state.js
CHANGED
|
@@ -12,28 +12,8 @@ function demoStateFile() {
|
|
|
12
12
|
function resolveStateFile(examId) {
|
|
13
13
|
return examId === 'demo-free' ? demoStateFile() : stateFile();
|
|
14
14
|
}
|
|
15
|
-
export function
|
|
16
|
-
|
|
17
|
-
const files = [stateFile(), demoStateFile()];
|
|
18
|
-
let latest = null;
|
|
19
|
-
let latestTime = 0;
|
|
20
|
-
for (const f of files) {
|
|
21
|
-
if (!existsSync(f))
|
|
22
|
-
continue;
|
|
23
|
-
try {
|
|
24
|
-
const state = JSON.parse(readFileSync(f, 'utf-8'));
|
|
25
|
-
const t = new Date(state.session.confirmedAt || state.session.startedAt).getTime();
|
|
26
|
-
if (t > latestTime) {
|
|
27
|
-
latest = state;
|
|
28
|
-
latestTime = t;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
catch { }
|
|
32
|
-
}
|
|
33
|
-
return latest;
|
|
34
|
-
}
|
|
35
|
-
export function getDemoState() {
|
|
36
|
-
const f = demoStateFile();
|
|
15
|
+
export function getRealExamState() {
|
|
16
|
+
const f = stateFile();
|
|
37
17
|
if (!existsSync(f))
|
|
38
18
|
return null;
|
|
39
19
|
try {
|
|
@@ -43,8 +23,8 @@ export function getDemoState() {
|
|
|
43
23
|
return null;
|
|
44
24
|
}
|
|
45
25
|
}
|
|
46
|
-
export function
|
|
47
|
-
const f =
|
|
26
|
+
export function getDemoState() {
|
|
27
|
+
const f = demoStateFile();
|
|
48
28
|
if (!existsSync(f))
|
|
49
29
|
return null;
|
|
50
30
|
try {
|
|
@@ -54,6 +34,18 @@ export function getRealExamState() {
|
|
|
54
34
|
return null;
|
|
55
35
|
}
|
|
56
36
|
}
|
|
37
|
+
export function getExamState() {
|
|
38
|
+
// Real exam ALWAYS takes priority over demo when both exist.
|
|
39
|
+
// Reasoning: real exam is token-gated, has a timer, and represents a serious
|
|
40
|
+
// commitment. Demo is casual practice. If a real exam is in progress, all
|
|
41
|
+
// shared commands (exam q N, exam answer, ai4ctf, ctf4ai) must target the
|
|
42
|
+
// real exam — never silently fall back to demo questions, even if demo was
|
|
43
|
+
// run more recently. (Demo→Exam→Finals progression principle, exam.md §0)
|
|
44
|
+
const real = getRealExamState();
|
|
45
|
+
if (real)
|
|
46
|
+
return real;
|
|
47
|
+
return getDemoState();
|
|
48
|
+
}
|
|
57
49
|
export function saveExamState(state) {
|
|
58
50
|
const f = resolveStateFile(state.session.examId);
|
|
59
51
|
writeFileSync(f, JSON.stringify(state, null, 2));
|