icoa-cli 2.19.633 → 2.19.635
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
|
-
export function localized(e,t){const r=(t||"en").slice(0,2).toLowerCase();if("en"===r)return e;const n=e[`_${r}`];if(!n||"object"!=typeof n)return e;const a=n,o={...e};for(const e of Object.keys(a))void 0!==a[e]&&(o[e]=a[e]);return o}export function overlayLanguages(e){const t=new Set;for(const r of e)for(const e of Object.keys(r)){const r=/^_([a-z]{2})$/.exec(e);r&&"en"!==r[1]&&t.add(r[1])}return[...t].sort()}export function isValidCurriculum(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.id&&"number"==typeof t.totalCards&&Array.isArray(t.cards)&&Array.isArray(t.modules)}import{readFileSync as e,writeFileSync as t,mkdirSync as r,existsSync as n,statSync as a,utimesSync as o}from"node:fs";import{join as i}from"node:path";import{homedir as c}from"node:os";import{getDeviceFingerprint as s}from"./access.js";import{getCliVersion as u}from"./version.js";import{httpFetch as l}from"./http.js";import{transportAdvice as d,transportCauseCode as p}from"./tls-trust.js";import{parseHometask as f}from"./learn-hometask.js";import{parseFaqs as m,parseReplies as _}from"./learn-replies.js";const g=i(c(),".icoa","learn-cache");export const LEARN_SERVER="https://practice.icoa2026.au";function y(e){const t=e.replace(/[^A-Za-z0-9_-]/g,"_");return i(g,`${t}.json`)}function h(e){const t=e.replace(/[^A-Za-z0-9_-]/g,"_");return i(g,`${t}.etag`)}let k=null;export function getLastCurriculumFailure(){return k}export async function loadCurriculumById(i,c,s=!1){"ctf4eai-12"===i&&(i="LEARNDEMO01");const l=function(t){const r=y(t);if(!n(r))return null;try{const t=a(r),n=Date.now()-t.mtimeMs;return{curriculum:JSON.parse(e(r,"utf-8")),ageMs:n}}catch{return null}}(i);if(!s&&l&&l.ageMs<6048e5&&isValidCurriculum(l.curriculum))return l.curriculum;k=null;const d=await async function(t,r){const a=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/curriculum/"+encodeURIComponent(t),o={},i=function(t){const r=h(t);if(!n(r))return null;try{return e(r,"utf-8").trim()||null}catch{return null}}(t);i&&(o["If-None-Match"]=i),r&&(o["X-Learn-Token"]=r.toUpperCase()),o["X-ICOA-Client"]=u();try{const e=await fetch(a,{headers:o,signal:AbortSignal.timeout(6e4)});if(304===e.status)return{kind:"unchanged"};if(404===e.status)return{kind:"notfound"};if(!e.ok)return{kind:"error"};const t=await e.json();if(!t.success||!t.data)return{kind:"error"};if(!isValidCurriculum(t.data))return{kind:"error"};const r=e.headers.get("etag")||e.headers.get("ETag")||void 0;return{kind:"fresh",curriculum:t.data,etag:r||void 0}}catch{return{kind:"error"}}}(i,c);return"fresh"===d.kind?(function(e,n,a){try{r(g,{recursive:!0}),t(y(e),JSON.stringify(n)),a&&t(h(e),a)}catch{}}(i,d.curriculum,d.etag),d.curriculum):"unchanged"===d.kind&&l&&isValidCurriculum(l.curriculum)?(function(e){try{const t=y(e);if(n(t)){const e=Date.now()/1e3;o(t,e,e)}}catch{}}(i),l.curriculum):l&&isValidCurriculum(l.curriculum)?l.curriculum:(k="notfound"===d.kind?"notfound":"offline",null)}export function validateResultShape(e){return{curriculumId:String(e.curriculum_id??""),status:String(e.status??""),validUntil:String(e.valid_until??""),aiEnabled:1===e.ai_enabled||!0===e.ai_enabled,aiBasicPerCard:"number"==typeof e.ai_basic_per_card&&e.ai_basic_per_card>0?e.ai_basic_per_card:3,gated:1===e.gated||!0===e.gated,replies:_(e.replies),hometask:f(e.hometask)}}export async function validateEAToken(e){const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/validate";try{const r=await l(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e.toUpperCase(),device_fingerprint:s()}),signal:AbortSignal.timeout(8e3)});if(!r.ok){const e=await r.json().catch(()=>({}));return{ok:!1,message:e.message||`HTTP ${r.status}`,code:e.code}}const n=await r.json();return n.success&&n.data?{ok:!0,...validateResultShape(n.data)}:{ok:!1,message:n.message||"Validation failed"}}catch(e){const t=e instanceof Error?e.message:String(e),r=p(e);return{ok:!1,message:`Network error: ${t}${r?` (${r})`:""}`,code:"network",advice:d(e)}}}export async function postFlowEvent(e,t,r,n){if("LEARNDEMO01"===e.toUpperCase())return;const a=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/flow/event";try{await l(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e.toUpperCase(),curriculum_id:t,card:r,fork_id:n.fork_id,first:n.first,final:n.final,walls:n.walls,ms:n.ms,choices:n.choices,started_at:n.started_at,device_fingerprint:s()}),signal:AbortSignal.timeout(5e3)})}catch{}}export async function syncProgress(e,t,r){if("LEARNDEMO01"===e.toUpperCase())return;const n=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/progress/"+e.toUpperCase();try{await l(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({card_number:t.card_number,event_type:t.event_type,mcq_answer:t.mcq_answer,mcq_correct:t.mcq_correct?1:0,check_answer:t.check_answer,check_correct:t.check_correct?1:0,time_on_card_ms:t.time_on_card_ms,device_fingerprint:s(),reply_ack:r&&r.length>0?r:void 0}),signal:AbortSignal.timeout(5e3)})}catch{}}export async function postFocusSession(e,t){if("LEARNDEMO01"===e.toUpperCase())return!0;const r=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/focus/"+e.toUpperCase();try{return(await l(r,{method:"POST",headers:{"Content-Type":"application/json","X-ICOA-Client":u()},body:JSON.stringify({...t,device_fingerprint:s()}),signal:AbortSignal.timeout(5e3)})).ok}catch{return!1}}export async function fetchServerProgress(e){if("LEARNDEMO01"===e.toUpperCase())return null;const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/progress/"+e.toUpperCase();try{const e=await l(t,{signal:AbortSignal.timeout(5e3)});if(!e.ok)return null;const r=await e.json();return r?.success&&Array.isArray(r.data?.events)?r.data.events:null}catch{return null}}export async function fetchCardFaqs(e){const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/faq/"+encodeURIComponent(e.toUpperCase());try{const e=await l(t,{signal:AbortSignal.timeout(5e3)});if(!e.ok)return[];const r=await e.json();return r.success&&r.data?m(r.data.faqs):[]}catch{return[]}}export async function syncCardFeedback(e,t){const r=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/feedback/"+e.toUpperCase();try{return(await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({curriculum_id:t.curriculum_id,card_number:t.card_number,feedback_text:t.feedback_text,time_on_card_ms:t.time_on_card_ms}),signal:AbortSignal.timeout(5e3)})).ok}catch{return!1}}
|
|
1
|
+
export function localized(e,t){const r=(t||"en").slice(0,2).toLowerCase();if("en"===r)return e;const n=e[`_${r}`];if(!n||"object"!=typeof n)return e;const a=n,o={...e};for(const e of Object.keys(a))void 0!==a[e]&&(o[e]=a[e]);return o}export function overlayLanguages(e){const t=new Set;for(const r of e)for(const e of Object.keys(r)){const r=/^_([a-z]{2})$/.exec(e);r&&"en"!==r[1]&&t.add(r[1])}return[...t].sort()}export function isValidCurriculum(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.id&&"number"==typeof t.totalCards&&Array.isArray(t.cards)&&Array.isArray(t.modules)}import{readFileSync as e,writeFileSync as t,mkdirSync as r,existsSync as n,statSync as a,utimesSync as o}from"node:fs";import{join as i}from"node:path";import{homedir as c}from"node:os";import{getDeviceFingerprint as s}from"./access.js";import{getCliVersion as u}from"./version.js";import{httpFetch as l}from"./http.js";import{transportAdvice as d,transportCauseCode as p}from"./tls-trust.js";import{parseHometask as f}from"./learn-hometask.js";import{parseFaqs as m,parseReplies as _}from"./learn-replies.js";const g=i(c(),".icoa","learn-cache");export const LEARN_SERVER="https://practice.icoa2026.au";function y(e){const t=e.replace(/[^A-Za-z0-9_-]/g,"_");return i(g,`${t}.json`)}function h(e){const t=e.replace(/[^A-Za-z0-9_-]/g,"_");return i(g,`${t}.etag`)}let k=null;export function getLastCurriculumFailure(){return k}export async function loadCurriculumById(i,c,s=!1){"ctf4eai-12"===i&&(i="LEARNDEMO01");const l=function(t){const r=y(t);if(!n(r))return null;try{const t=a(r),n=Date.now()-t.mtimeMs;return{curriculum:JSON.parse(e(r,"utf-8")),ageMs:n}}catch{return null}}(i);if(!s&&l&&l.ageMs<6048e5&&isValidCurriculum(l.curriculum))return l.curriculum;k=null;const d=await async function(t,r){const a=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/curriculum/"+encodeURIComponent(t),o={},i=function(t){const r=h(t);if(!n(r))return null;try{return e(r,"utf-8").trim()||null}catch{return null}}(t);i&&(o["If-None-Match"]=i),r&&(o["X-Learn-Token"]=r.toUpperCase()),o["X-ICOA-Client"]=u();try{const e=await fetch(a,{headers:o,signal:AbortSignal.timeout(6e4)});if(304===e.status)return{kind:"unchanged"};if(404===e.status)return{kind:"notfound"};if(!e.ok)return{kind:"error"};const t=await e.json();if(!t.success||!t.data)return{kind:"error"};if(!isValidCurriculum(t.data))return{kind:"error"};const r=e.headers.get("etag")||e.headers.get("ETag")||void 0;return{kind:"fresh",curriculum:t.data,etag:r||void 0}}catch{return{kind:"error"}}}(i,c);return"fresh"===d.kind?(function(e,n,a){try{r(g,{recursive:!0}),t(y(e),JSON.stringify(n)),a&&t(h(e),a)}catch{}}(i,d.curriculum,d.etag),d.curriculum):"unchanged"===d.kind&&l&&isValidCurriculum(l.curriculum)?(function(e){try{const t=y(e);if(n(t)){const e=Date.now()/1e3;o(t,e,e)}}catch{}}(i),l.curriculum):l&&isValidCurriculum(l.curriculum)?l.curriculum:(k="notfound"===d.kind?"notfound":"offline",null)}export function parseUpgradedTo(e){if(!e||"object"!=typeof e)return null;const t=e,r=String(t.token??"").toUpperCase(),n=String(t.curriculum_id??"");return/^[A-Z]{2}[A-Z0-9]{8}$/.test(r)&&n?{token:r,curriculumId:n}:null}export function validateResultShape(e){return{curriculumId:String(e.curriculum_id??""),status:String(e.status??""),validUntil:String(e.valid_until??""),aiEnabled:1===e.ai_enabled||!0===e.ai_enabled,aiBasicPerCard:"number"==typeof e.ai_basic_per_card&&e.ai_basic_per_card>0?e.ai_basic_per_card:3,gated:1===e.gated||!0===e.gated,replies:_(e.replies),hometask:f(e.hometask),upgradedTo:parseUpgradedTo(e.upgraded_to)}}export async function validateEAToken(e){const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/validate";try{const r=await l(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e.toUpperCase(),device_fingerprint:s()}),signal:AbortSignal.timeout(8e3)});if(!r.ok){const e=await r.json().catch(()=>({}));return{ok:!1,message:e.message||`HTTP ${r.status}`,code:e.code}}const n=await r.json();return n.success&&n.data?{ok:!0,...validateResultShape(n.data)}:{ok:!1,message:n.message||"Validation failed"}}catch(e){const t=e instanceof Error?e.message:String(e),r=p(e);return{ok:!1,message:`Network error: ${t}${r?` (${r})`:""}`,code:"network",advice:d(e)}}}export async function postFlowEvent(e,t,r,n){if("LEARNDEMO01"===e.toUpperCase())return;const a=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/flow/event";try{await l(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e.toUpperCase(),curriculum_id:t,card:r,fork_id:n.fork_id,first:n.first,final:n.final,walls:n.walls,ms:n.ms,choices:n.choices,started_at:n.started_at,device_fingerprint:s()}),signal:AbortSignal.timeout(5e3)})}catch{}}export async function syncProgress(e,t,r){if("LEARNDEMO01"===e.toUpperCase())return;const n=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/progress/"+e.toUpperCase();try{await l(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({card_number:t.card_number,event_type:t.event_type,mcq_answer:t.mcq_answer,mcq_correct:t.mcq_correct?1:0,check_answer:t.check_answer,check_correct:t.check_correct?1:0,time_on_card_ms:t.time_on_card_ms,device_fingerprint:s(),reply_ack:r&&r.length>0?r:void 0}),signal:AbortSignal.timeout(5e3)})}catch{}}export async function postFocusSession(e,t){if("LEARNDEMO01"===e.toUpperCase())return!0;const r=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/focus/"+e.toUpperCase();try{return(await l(r,{method:"POST",headers:{"Content-Type":"application/json","X-ICOA-Client":u()},body:JSON.stringify({...t,device_fingerprint:s()}),signal:AbortSignal.timeout(5e3)})).ok}catch{return!1}}export async function fetchServerProgress(e){if("LEARNDEMO01"===e.toUpperCase())return null;const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/progress/"+e.toUpperCase();try{const e=await l(t,{signal:AbortSignal.timeout(5e3)});if(!e.ok)return null;const r=await e.json();return r?.success&&Array.isArray(r.data?.events)?r.data.events:null}catch{return null}}export async function fetchCardFaqs(e){const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/faq/"+encodeURIComponent(e.toUpperCase());try{const e=await l(t,{signal:AbortSignal.timeout(5e3)});if(!e.ok)return[];const r=await e.json();return r.success&&r.data?m(r.data.faqs):[]}catch{return[]}}export async function syncCardFeedback(e,t){const r=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/feedback/"+e.toUpperCase();try{return(await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({curriculum_id:t.curriculum_id,card_number:t.card_number,feedback_text:t.feedback_text,time_on_card_ms:t.time_on_card_ms}),signal:AbortSignal.timeout(5e3)})).ok}catch{return!1}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "icoa-cli",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.635",
|
|
4
4
|
"description": "ICOA CLI — AI-native competition runtime of the International Cyber Olympiad in AI: learn, practise, and compete in AI & cybersecurity from the terminal (AI4CTF · CTF4AI · CTF4EAI)",
|
|
5
5
|
"author": "Charlie Zhu",
|
|
6
6
|
"type": "module",
|