icoa-cli 2.19.83 → 2.19.84

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.
@@ -883,15 +883,9 @@ export function registerExamCommand(program) {
883
883
  }
884
884
  return;
885
885
  }
886
- // Eliminate one wrong option (async for demo answers)
887
- const doEliminate = (correct) => {
888
- const wrongRemaining = remaining.filter((k) => k !== correct && !eliminated.includes(k));
889
- if (wrongRemaining.length === 0)
890
- return;
891
- // Pick random wrong option to eliminate
892
- const toRemove = wrongRemaining[Math.floor(Math.random() * wrongRemaining.length)];
886
+ // Apply elimination of a specific option
887
+ const applyEliminate = (toRemove) => {
893
888
  eliminated.push(toRemove);
894
- // Update state
895
889
  if (!help.eliminated[currentQ])
896
890
  help.eliminated[currentQ] = [];
897
891
  help.eliminated[currentQ] = eliminated;
@@ -909,31 +903,42 @@ export function registerExamCommand(program) {
909
903
  console.log(chalk.yellow(` 💡 Option ${toRemove} eliminated!`) + chalk.gray(` (help ${help.used}/${help.max})`));
910
904
  printQuestion(q, state.answers[q.number]);
911
905
  };
906
+ // Pick a random wrong option to eliminate (needs correct answer)
907
+ const doEliminate = (correct) => {
908
+ const wrongRemaining = remaining.filter((k) => k !== correct && !eliminated.includes(k));
909
+ if (wrongRemaining.length === 0)
910
+ return;
911
+ applyEliminate(wrongRemaining[Math.floor(Math.random() * wrongRemaining.length)]);
912
+ };
912
913
  if (state.session.examId === 'demo-free' && q.answer) {
913
914
  doEliminate(q.answer);
914
915
  }
915
916
  else {
916
- // For server exams, we don't know the answer — eliminate random non-selected option
917
- const userAnswer = state.answers[currentQ];
918
- const candidates = remaining.filter((k) => k !== userAnswer);
919
- const toRemove = candidates[Math.floor(Math.random() * candidates.length)];
920
- eliminated.push(toRemove);
921
- if (!help.eliminated[currentQ])
922
- help.eliminated[currentQ] = [];
923
- help.eliminated[currentQ] = eliminated;
924
- help.perQ[currentQ] = qHelps + 1;
925
- help.used++;
926
- state._helpUsed = help.used;
927
- state._helpMax = help.max;
928
- state._helpPerQ = help.perQ;
929
- state._eliminated = help.eliminated;
930
- if (!state.interactions)
931
- state.interactions = [];
932
- state.interactions.push({ ts: new Date().toISOString(), q: currentQ, type: 'help_used', result: `eliminated ${toRemove}` });
933
- saveExamState(state);
934
- console.log();
935
- console.log(chalk.yellow(` 💡 Option ${toRemove} eliminated!`) + chalk.gray(` (help ${help.used}/${help.max})`));
936
- printQuestion(q, state.answers[q.number]);
917
+ // Server-authoritative: ask server which wrong option to eliminate
918
+ const config = getConfig();
919
+ const serverUrl = config.ctfdUrl || 'https://practice.icoa2026.au';
920
+ const token = state.session?.token || '';
921
+ try {
922
+ const res = await fetch(`${serverUrl}/api/icoa/exams/${state.session.examId}/help`, {
923
+ method: 'POST',
924
+ headers: { 'Content-Type': 'application/json', 'User-Agent': 'icoa-cli' },
925
+ body: JSON.stringify({ token, question: currentQ, eliminated }),
926
+ signal: AbortSignal.timeout(5000),
927
+ });
928
+ const json = await res.json();
929
+ const toRemove = json?.data?.eliminate;
930
+ if (toRemove && ['A', 'B', 'C', 'D'].includes(toRemove)) {
931
+ applyEliminate(toRemove);
932
+ }
933
+ else {
934
+ console.log();
935
+ console.log(chalk.gray(' Server did not return a valid option. Try again.'));
936
+ }
937
+ }
938
+ catch {
939
+ console.log();
940
+ console.log(chalk.gray(' Could not reach server for help. Check your connection.'));
941
+ }
937
942
  }
938
943
  });
939
944
  // ─── exam more-help ───
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.83",
3
+ "version": "2.19.84",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {