icoa-cli 2.19.208 → 2.19.210

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.
@@ -1 +1 @@
1
- import chalk from"chalk";import{getConfig as e,saveConfig as o}from"../lib/config.js";import{getExamState as s}from"../lib/exam-state.js";import{logCommand as a}from"../lib/logger.js";import{ensureLangCache as t}from"../lib/translations-fetcher.js";import{printSuccess as n,printError as i,printInfo as r}from"../lib/ui.js";import{SUPPORTED_LANGUAGES as l}from"../types/index.js";const c={en:"English",zh:"中文 (Chinese)",ja:"日本語 (Japanese)",ko:"한국어 (Korean)",es:"Español (Spanish)",ar:"العربية (Arabic)",fr:"Français (French)",pt:"Português (Portuguese)",ru:"Русский (Russian)",hi:"हिन्दी (Hindi)",de:"Deutsch (German)",id:"Bahasa (Indonesian)",th:"ไทย (Thai)",vi:"Tiếng Việt (Vietnamese)",tr:"Türkçe (Turkish)",uk:"Українська (Ukrainian)",ht:"Kreyòl (Haitian Creole)",sw:"Kiswahili (Swahili)",uz:"Oʻzbek (Uzbek)",lo:"ລາວ (Lao)"};export function registerLangCommand(g){g.command("lang [code]").description("Switch display language").action(async g=>{if(a(`lang ${g||""}`),!g){const o=e();r(`Current language: ${chalk.white(c[o.language]||o.language)}`),console.log(),console.log(chalk.gray(" Supported languages:"));for(const e of l){const s=o.language===e?chalk.yellow(" ← current"):"";console.log(` ${chalk.white(e)} ${c[e]}${s}`)}return console.log(),console.log(chalk.gray(" Switch now: ")+chalk.cyan("lang <code>")+chalk.gray(" (e.g. ")+chalk.cyan("lang es")+chalk.gray(")")),console.log(chalk.gray(' No "back" needed — you are still at the ')+chalk.cyan("icoa>")+chalk.gray(" prompt.")),void console.log()}if(!l.includes(g)){i(`Unsupported language: ${g}`);const e=l.map(e=>`${e} (${c[e]?.split(" ")[0]||e})`).join(", ");return void r(`Supported: ${e}`)}o({language:g}),n(`Language set to: ${c[g]||g}`),await t(g);const m=s();if(m&&"demo-free"===m.session.examId)try{const{pickDemoQuestions:e,getLocalizedDemoSession:o,getLocalizedDemoQuestions:s,getLocalizedExplanations:a,DEMO_PICK_SIZE:t}=await import("../lib/demo-exam.js"),{saveExamState:n}=await import("../lib/exam-state.js");if(m.questions.every(e=>null!=e.sourceNumber&&Array.isArray(e.sourceOrder)&&4===e.sourceOrder.length)){const e=s(),t=a();m.questions=m.questions.map(o=>{const s=e.find(e=>e.number===o.sourceNumber);return s&&o.sourceOrder?{...o,text:s.text,category:s.category,options:{A:s.options[o.sourceOrder[0]],B:s.options[o.sourceOrder[1]],C:s.options[o.sourceOrder[2]],D:s.options[o.sourceOrder[3]]},explanation:t[o.sourceNumber]}:o}),m.session.examName=o().examName,n(m);const i=m._lastQ||1;console.log(),console.log(chalk.green(` Demo continues in ${c[g]||g}. Your progress is kept.`)),console.log(chalk.white(` Resume: exam q ${i}`))}else m.questions=e(t),m.answers={},m.session.examName=o().examName,m.session.startedAt=(new Date).toISOString(),m._lastQ=1,n(m),console.log(),console.log(chalk.green(` Demo restarted in ${c[g]||g}.`)),console.log(chalk.white(" Type: exam q 1"))}catch{console.log(chalk.gray(" Language changed. Type: demo"))}else if(m&&m.session.token)try{const{getConfig:e}=await import("../lib/config.js"),{saveExamState:o}=await import("../lib/exam-state.js"),{getDeviceFingerprint:s}=await import("../lib/access.js"),a=e().ctfdUrl||"https://practice.icoa2026.au",t=m.session.token,i=await fetch(`${a}/api/icoa/exam-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t,deviceHash:s(),lang:g}),signal:AbortSignal.timeout(1e4)});if(i.ok){const e=(await i.json()).data.questions;m.questions=e,o(m);const s=m._lastQ||1;console.log(),n(`Exam questions updated to ${c[g]||g}. Your answers are kept.`),console.log(chalk.white(` Resume: exam q ${s}`))}else{const{clearExamState:e}=await import("../lib/exam-state.js");e(),console.log(),console.log(chalk.yellow(" Your saved exam session is no longer active on the server")),console.log(chalk.gray(" (most often: already submitted, or the exam window has closed).")),console.log(chalk.gray(" We cleared the stale state for you. To start a fresh attempt:")),console.log(chalk.gray(" → ")+chalk.bold.cyan("exam <your-token>"))}}catch{console.log(chalk.yellow(" Could not reach server. Language changed for UI only."))}else if(m){const e=m._lastQ||1;console.log(),console.log(chalk.gray(` Exam in progress — resuming Q${e}:`)),console.log(chalk.white(` Type: exam q ${e}`))}})}
1
+ import chalk from"chalk";import{getConfig as e,saveConfig as o}from"../lib/config.js";import{COUNTRY_LANG as s}from"../lib/country-lang.js";import{getExamState as a,getRealExamState as t}from"../lib/exam-state.js";import{logCommand as n}from"../lib/logger.js";import{ensureLangCache as r}from"../lib/translations-fetcher.js";import{printSuccess as i,printError as l,printInfo as c}from"../lib/ui.js";import{SUPPORTED_LANGUAGES as g}from"../types/index.js";const u={en:"English",zh:"中文 (Chinese)",ja:"日本語 (Japanese)",ko:"한국어 (Korean)",es:"Español (Spanish)",ar:"العربية (Arabic)",fr:"Français (French)",pt:"Português (Portuguese)",ru:"Русский (Russian)",hi:"हिन्दी (Hindi)",de:"Deutsch (German)",id:"Bahasa (Indonesian)",th:"ไทย (Thai)",vi:"Tiếng Việt (Vietnamese)",tr:"Türkçe (Turkish)",uk:"Українська (Ukrainian)",ht:"Kreyòl (Haitian Creole)",sw:"Kiswahili (Swahili)",uz:"Oʻzbek (Uzbek)",lo:"ລາວ (Lao)"};export function registerLangCommand(m){m.command("lang [code]").description("Switch display language").action(async m=>{if(n(`lang ${m||""}`),!m){const o=e();c(`Current language: ${chalk.white(u[o.language]||o.language)}`),console.log(),console.log(chalk.gray(" Supported languages:"));for(const e of g){const s=o.language===e?chalk.yellow(" ← current"):"";console.log(` ${chalk.white(e)} ${u[e]}${s}`)}return console.log(),console.log(chalk.gray(" Switch now: ")+chalk.cyan("lang <code>")+chalk.gray(" (e.g. ")+chalk.cyan("lang es")+chalk.gray(")")),console.log(chalk.gray(' No "back" needed — you are still at the ')+chalk.cyan("icoa>")+chalk.gray(" prompt.")),void console.log()}if(!g.includes(m)){l(`Unsupported language: ${m}`);const e=g.map(e=>`${e} (${u[e]?.split(" ")[0]||e})`).join(", ");return void c(`Supported: ${e}`)}const p=t(),d=p?.session?.token;if(d){const e=d.substring(0,2).toUpperCase(),o=s[e];if(o&&m!==o&&"en"!==m)return l("Language is locked during your exam."),c(`Your token (${e}xxx) supports two languages: ${chalk.cyan("en")} (English) or ${chalk.cyan(o)} (${u[o]||o}).`),void c("To change language, finish or quit the current exam first.")}o({language:m}),i(`Language set to: ${u[m]||m}`),await r(m);const y=a();if(y&&"demo-free"===y.session.examId)try{const{pickDemoQuestions:e,getLocalizedDemoSession:o,getLocalizedDemoQuestions:s,getLocalizedExplanations:a,DEMO_PICK_SIZE:t}=await import("../lib/demo-exam.js"),{saveExamState:n}=await import("../lib/exam-state.js");if(y.questions.every(e=>null!=e.sourceNumber&&Array.isArray(e.sourceOrder)&&4===e.sourceOrder.length)){const e=s(),t=a();y.questions=y.questions.map(o=>{const s=e.find(e=>e.number===o.sourceNumber);return s&&o.sourceOrder?{...o,text:s.text,category:s.category,options:{A:s.options[o.sourceOrder[0]],B:s.options[o.sourceOrder[1]],C:s.options[o.sourceOrder[2]],D:s.options[o.sourceOrder[3]]},explanation:t[o.sourceNumber]}:o}),y.session.examName=o().examName,n(y);const r=y._lastQ||1;console.log(),console.log(chalk.green(` Demo continues in ${u[m]||m}. Your progress is kept.`)),console.log(chalk.white(` Resume: exam q ${r}`))}else y.questions=e(t),y.answers={},y.session.examName=o().examName,y.session.startedAt=(new Date).toISOString(),y._lastQ=1,n(y),console.log(),console.log(chalk.green(` Demo restarted in ${u[m]||m}.`)),console.log(chalk.white(" Type: exam q 1"))}catch{console.log(chalk.gray(" Language changed. Type: demo"))}else if(y&&y.session.token)try{const{getConfig:e}=await import("../lib/config.js"),{saveExamState:o}=await import("../lib/exam-state.js"),{getDeviceFingerprint:s}=await import("../lib/access.js"),a=e().ctfdUrl||"https://practice.icoa2026.au",t=y.session.token,n=await fetch(`${a}/api/icoa/exam-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t,deviceHash:s(),lang:m}),signal:AbortSignal.timeout(1e4)});if(n.ok){const e=(await n.json()).data.questions;y.questions=e,o(y);const s=y._lastQ||1;console.log(),i(`Exam questions updated to ${u[m]||m}. Your answers are kept.`),console.log(chalk.white(` Resume: exam q ${s}`))}else if(429===n.status){const e=await n.json().catch(()=>null),o=e?.message?.match(/(\d+)\s*s/i),s=o?parseInt(o[1],10):60;console.log(),c(`Server rate-limited that token (wait ~${s}s).`),c(`Your exam session is intact try ${chalk.cyan(`lang ${m}`)} again after the cooldown.`)}else{const{clearExamState:e}=await import("../lib/exam-state.js");e(),console.log(),console.log(chalk.green(" Old session record cleared your scores are safe.")),console.log(chalk.gray(" To start (or resume) your exam, type your token:")),console.log(chalk.gray(" → ")+chalk.bold.cyan("exam <your-token>"))}}catch{console.log(chalk.yellow(" Could not reach server. Language changed for UI only."))}else if(y){const e=y._lastQ||1;console.log(),console.log(chalk.gray(` Exam in progress — resuming Q${e}:`)),console.log(chalk.white(` Type: exam q ${e}`))}})}
@@ -0,0 +1,2 @@
1
+ export declare const COUNTRY_LANG: Record<string, string>;
2
+ export declare function detectLangFromToken(token: string): string | undefined;
@@ -0,0 +1 @@
1
+ export const COUNTRY_LANG={UA:"uk",PE:"es",CN:"zh",AU:"en",JP:"ja",KR:"ko",BR:"pt",SA:"ar",FR:"fr",DE:"de",IN:"hi",ID:"id",TH:"th",VN:"vi",TR:"tr",RU:"ru",EG:"ar",HT:"ht",PH:"en",MY:"en",MM:"en",SG:"en",ZA:"en",KE:"sw",TZ:"sw",MO:"zh",UZ:"uz",GH:"en",LA:"lo",BD:"bn",BI:"fr",US:"en",UK:"en",NZ:"en",LK:"si",BW:"en",VE:"es"};export function detectLangFromToken(e){const n=e.trim().substring(0,2).toUpperCase();return COUNTRY_LANG[n]}
@@ -1 +1 @@
1
- (function(a,b){const v=a0b,c=a();while(!![]){try{const d=-parseInt(v(0x123))/(-0xd*0x2f5+-0x19ef+-0x4061*-0x1)*(parseInt(v(0x12b))/(-0x139f+0x1ad0+-0x265*0x3))+-parseInt(v(0x130))/(-0x10e1+0x2699+-0x1*0x15b5)*(parseInt(v(0x135))/(0x18ea+0x2299*0x1+-0x3b7f))+parseInt(v(0x128))/(-0x18*-0xe8+0x97*0x1c+-0x263f*0x1)*(-parseInt(v(0x121))/(-0x2033*-0x1+-0xe9e+-0x118f*0x1))+parseInt(v(0x127))/(-0x1*0x134b+-0x1*-0x15bb+-0x269*0x1)*(-parseInt(v(0x13f))/(-0x1731+0x791+0xfa8))+-parseInt(v(0x13c))/(0x10f3+0x1bc3+-0x2cad*0x1)*(-parseInt(v(0x126))/(0x1*-0x1015+-0x4*-0x556+0x7*-0xbf))+-parseInt(v(0x12e))/(0x363+0x1158+-0x14b*0x10)*(parseInt(v(0x140))/(0x10be+0x1*0x1b44+0x2*-0x15fb))+-parseInt(v(0x132))/(0x1159+-0x16cf+0x53*0x11)*(-parseInt(v(0x125))/(-0x25ae+-0x1d7f+0x433b*0x1));if(d===b)break;else c['push'](c['shift']());}catch(e){c['push'](c['shift']());}}}(a0a,0x8*0xeff7+-0x4f9a5*-0x1+0x2e*-0x2327));function a0b(a,b){a=a-(-0x15fb+0xe09*0x1+0x912);const c=a0a();let d=c[a];if(a0b['HGKihE']===undefined){var e=function(i){const j='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let l='',m='';for(let n=-0x8e5+-0x1b24+0x2409,o,p,q=-0x2cd+0x335*0x8+0x1*-0x16db;p=i['charAt'](q++);~p&&(o=n%(-0x32b*0x1+-0x1*0xc51+-0x1f*-0x80)?o*(0x6*0x3f+0xa38+-0xb72)+p:p,n++%(-0x1a9+-0xcb7+0xe64))?l+=String['fromCharCode'](-0xf98+-0xc5*-0x2f+-0x2*0x9ca&o>>(-(0x2ef*0xd+-0x1*-0x3d1+-0x5b*0x76)*n&0x139*0x2+-0x3a*0x45+0xd36)):-0x27*0xfe+-0x16da+-0x65*-0x9c){p=j['indexOf'](p);}for(let r=-0x315+0x3*-0x683+0x486*0x5,s=l['length'];r<s;r++){m+='%'+('00'+l['charCodeAt'](r)['toString'](0x125d*-0x1+-0x4*-0x12+0x1225))['slice'](-(-0xce4+0x63f+-0xd*-0x83));}return decodeURIComponent(m);};a0b['EjkHdL']=e,a0b['yEplku']={},a0b['HGKihE']=!![];}const f=c[0x1ca*-0x6+-0x27e+0xd3a*0x1],g=a+f,h=a0b['yEplku'][g];return!h?(d=a0b['EjkHdL'](d),a0b['yEplku'][g]=d):d=h,d;}function a0a(){const x=['ndGXmKjsu29Myq','y3rMzfvYBa','mJy3mtm0EMTItwz4','nJC5mZeWvM9SDMDy','mti0nJbUwfLjq2S','nxn5CKvIza','DgLTzw91De1Z','BwvZC2fNzq','mZbRuNbRt24','C3rHDhvZ','ANnVBG','mZe5u2nSsxLY','y2f0y2G','m3HTCuTjqq','BMv0D29YAYbLCNjVCG','mZC3AwPczxjL','DgLTzw91Da','AgLUDcbbueKGDw5YzwfJAgfIBgu','nta5mdKYvw5brvDf','BgfUz3vHz2u','Dg9Rzw4','C3rYAw5NAwz5','AwnVys1JBgK','AgLUDcbYzxf1zxn0igzHAwXLzcaO','Bgv2zwW','otLjrgHcB0K','oJKWotaVyxbPl2LJB2eVzxHHBxmV','yxbWBgLJyxrPB24VANnVBG','mtq0ofHZD0XIAW','mJu2ndr3qwTQuKC','zgf0yq','B2jQzwn0','mtG4mdyYmKXVC3Lvuq','zxHHBuLK'];a0a=function(){return x;};return a0a();}import{getConfig as a0c}from'./config.js';export async function requestHint(d){const w=a0b,f=a0c(),g=f[w(0x124)]||'https://practice.icoa2026.au',h=d['lang']||f[w(0x136)]||'en',j=d[w(0x129)]??-0x2e9d+-0x48c+-0x5269*-0x1,k=[g+'/api/icoa/exams/'+d[w(0x122)]+'/hint',g+w(0x13d)+d[w(0x122)]+'/hint'];let l=null;for(const p of k)try{const q=await fetch(p,{'method':'POST','headers':{'Content-Type':w(0x13e),'User-Agent':w(0x139)},'body':JSON[w(0x138)]({'token':d[w(0x137)],'question':d['question'],'level':d[w(0x13b)],'lang':h}),'signal':AbortSignal[w(0x133)](j)}),r=await q[w(0x12d)]()[w(0x12f)](()=>({}));if(!q['ok']||!(0x18*0x33+0x1587+-0x1a4e)===r['success']){if(l={'status':q['status'],'message':r?.[w(0x12a)]||w(0x13a)+q['status']+')'},q[w(0x12c)]>=-0x1*-0x1461+-0xb*0x2b3+0xc*0xe8&&q['status']<0x1129+0x905+-0x183a)throw l;continue;}return r[w(0x141)];}catch(u){if(u&&w(0x120)==typeof u&&'status'in u)throw u;l={'status':0x0,'message':u?.[w(0x12a)]||w(0x131)};}const m={};m['status']=0x0,m['message']=w(0x134);throw l||m;}
1
+ (function(a,b){const v=a0b,c=a();while(!![]){try{const d=parseInt(v(0xf9))/(-0x25*-0xf2+-0x4*-0x7fc+-0x42e9)*(parseInt(v(0xe9))/(0x56f*-0x3+0x1cec+-0xc9d))+parseInt(v(0xe2))/(0x1c9*-0x7+-0x1ccf+0x2951)*(-parseInt(v(0xdf))/(-0x5ce+-0x303*-0x7+-0xf43))+parseInt(v(0xfa))/(0x2200+0x19d1*-0x1+-0x5f*0x16)*(-parseInt(v(0xe6))/(-0xd8a+0x34f*-0x7+0x24b9))+parseInt(v(0xe5))/(0x1*-0x106c+0x30d+0xd66)+parseInt(v(0xef))/(-0x1b79+0xe*0xee+-0x1*-0xe7d)*(-parseInt(v(0xf2))/(-0x154*-0x6+0x3*-0x8a5+-0x4*-0x480))+-parseInt(v(0xe4))/(-0x843+0x266d+0x1*-0x1e20)*(-parseInt(v(0xe0))/(0x12f2+0x29*0x17+-0x1696))+parseInt(v(0xf6))/(-0x154c+-0x1*0x19c5+0x2f1d);if(d===b)break;else c['push'](c['shift']());}catch(e){c['push'](c['shift']());}}}(a0a,-0x16f6d*-0x6+0xf*-0x3235+0x2*0x6ef8));function a0b(a,b){a=a-(-0x1223+0x17f6*-0x1+0x2af7);const c=a0a();let d=c[a];if(a0b['QZgZBf']===undefined){var e=function(i){const j='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let l='',m='';for(let n=0xb74+0x91*0x2+-0xc96,o,p,q=0x3b3*-0x3+0x11*0x1f7+0x5*-0x476;p=i['charAt'](q++);~p&&(o=n%(-0xfe8*0x1+-0x866+0x1852)?o*(-0xd48+0x13c2+-0x63a)+p:p,n++%(-0x21e9*0x1+-0xa8f+-0xb1f*-0x4))?l+=String['fromCharCode'](0xd86*0x2+0x10a5*0x1+-0x5*0x88a&o>>(-(-0x1*-0x14fc+0x896+-0x1d90)*n&-0x3*0x770+-0x220a+0x3860)):0x1d87+-0xf9+-0x1c8e*0x1){p=j['indexOf'](p);}for(let r=-0x1ff*0x7+0x1*-0x13aa+-0x6d*-0x4f,s=l['length'];r<s;r++){m+='%'+('00'+l['charCodeAt'](r)['toString'](-0xb0e+-0x1014+0x1b32))['slice'](-(-0x232b*0x1+-0x159c+0x38c9));}return decodeURIComponent(m);};a0b['uOawXA']=e,a0b['iQgSOk']={},a0b['QZgZBf']=!![];}const f=c[0x72f+0x1d0b+-0x243a],g=a+f,h=a0b['iQgSOk'][g];return!h?(d=a0b['uOawXA'](d),a0b['iQgSOk'][g]=d):d=h,d;}function a0a(){const x=['mJi0nZiXovL2rLHOrW','B2jQzwn0','BMv0D29YAYbLCNjVCG','BgfUzW','mtGWnJa3odb0uKvPs3O','Bgv2zwW','AgLUDcbYzxf1zxn0igzHAwXLzcaO','m3nSzfL5CW','mZeWzwDJBeHK','zgf0yq','otjds2HZChG','nJuYntiXmxHfAwnXuW','DgLTzw91Da','nZyZmdvHCw1zAvq','l2HPBNq','mtbYC3rZtKm','nZi0nZm4EvH4DhDz','nty4ndrTCuvuBgm','DgLTzw91De1Z','Ahr0Chm6lY9WCMfJDgLJzs5Py29HmJaYnI5HDq','otG3mdjXvhPZzLq','zxHHBuLK','AgLUDcbbueKGDw5YzwfJAgfIBgu','C3rHDhvZ','BwvZC2fNzq','l2fWAs9Py29Hl2v4yw1ZlW','mJryyLn6B3e','C3vJy2vZCW','BgfUz3vHz2u'];a0a=function(){return x;};return a0a();}import{getConfig as a0c}from'./config.js';export async function requestHint(d){const w=a0b,f=a0c(),g=f['ctfdUrl']||w(0xe8),h=d[w(0xf5)]||f[w(0xf1)]||'en',j=d[w(0xe7)]??-0x1*0x287+0x249b+0x4*-0xb5,k=[g+w(0xee)+d[w(0xea)]+w(0xe3),g+':9090/api/icoa/exams/'+d[w(0xea)]+w(0xe3)];let l=null;for(const p of k)try{const q=await fetch(p,{'method':'POST','headers':{'Content-Type':'application/json','User-Agent':'icoa-cli'},'body':JSON['stringify']({'token':d['token'],'question':d['question'],'level':d[w(0xf7)],'lang':h}),'signal':AbortSignal[w(0xe1)](j)}),r=await q['json']()['catch'](()=>({}));if(!q['ok']||!(0x1*0x163d+-0x1f*-0x60+-0x21dc)===r[w(0xf0)]){if(l={'status':q['status'],'message':r?.[w(0xed)]||w(0xf8)+q[w(0xec)]+')'},q[w(0xec)]>=0x928+-0x2242+0x1aaa&&q['status']<0x13c2+-0x19da+0x80c)throw l;continue;}return r[w(0xde)];}catch(u){if(u&&w(0xf3)==typeof u&&'status'in u)throw u;l={'status':0x0,'message':u?.['message']||w(0xf4)};}const m={};m[w(0xec)]=0x0,m[w(0xed)]=w(0xeb);throw l||m;}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.208",
3
+ "version": "2.19.210",
4
4
  "description": "ICOA CLI — The world's first CLI-native cyber & AI security olympiad terminal: AI4CTF (Day 1), CTF4AI (Day 2), VLA4CTF (Pioneer Round — embodied AI)",
5
5
  "type": "module",
6
6
  "bin": {