icoa-cli 2.19.535 โ†’ 2.19.536

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{existsSync as e,readFileSync as t,writeFileSync as r}from"node:fs";import{join as o}from"node:path";import chalk from"chalk";import s from"string-width";import{getIcoaDir as n}from"./config.js";import{detectCaps as a}from"./render-card.js";import{fetchLearnProfile as i}from"./learn-profile.js";const c=()=>o(n(),"profile-cache.json");export async function fetchProfileCached(o){const s=o.toUpperCase();let n={};try{if(e(c())){const e=JSON.parse(t(c(),"utf8"));e&&"object"==typeof e&&!("token"in e)&&(n=e);const r=n[s];if(r&&"number"==typeof r.ts&&Date.now()-r.ts<6e5&&r.profile)return r.profile}}catch{}const a=await i(s,"me");if("ok"!==a.kind)return null;try{n[s]={ts:Date.now(),profile:a.profile},r(c(),JSON.stringify(n))}catch{}return a.profile}export async function fetchProfilesForLocalTokens(e){const t=new Set,r=[];for(const o of e){const e=o.toUpperCase();if(t.has(e)||!/^[A-Z]{2}[A-Z0-9]{8}$/.test(e)||/DEMO01$/.test(e))continue;if(t.add(e),t.size>6)break;const s=await fetchProfileCached(e);s&&r.push(s)}return r}export function dropProfileCache(){try{r(c(),"{}")}catch{}}function u(e){const t=Math.max(48,Math.min(e,72)),r="T0"===a().tier,o=(r?"=":"โ”").repeat(Math.min(34,t-8)),n=Math.min(28,t-28);return{W:t,ascii:r,rule:o,center:e=>" ".repeat(Math.max(0,Math.floor((t-s(e))/2)))+e,row:(e,t)=>chalk.gray(` ${e} ${".".repeat(Math.max(2,n-s(e)))} `)+t}}export function doorStoryLines(e,t,r){const{ascii:o,rule:s,center:n,row:a}=u(t),i=(e,t)=>o?t:e,c=[];c.push(chalk.cyan(n(s))),c.push(chalk.gray(n("your story so far"))),c.push(chalk.cyan(n(s)));const p=[];e.streak_days>0?p.push(`${i("๐Ÿ”ฅ","streak")} ${e.streak_days}-day streak`):p.push("one card today starts a streak"),e.active_days>0&&p.push(`${e.active_days} active days`),e.linked>0&&p.push(`${i("๐Ÿ”—","linked")} ${e.linked+1} tokens`),c.push(a("Tonight",chalk.white(p.join(" ยท "))));for(const t of e.ladders){let e=!1;const r=t.steps.map(t=>"done"===t.state?(e=!0,chalk.green(`${t.curriculum_id} ${i("๐Ÿ","done")}`)):"in"===t.state?(e=!0,chalk.bold.white(`${t.curriculum_id} ${t.cards_done}/${t.total_cards}`)):e?chalk.gray(`${t.curriculum_id} (next)`):chalk.gray(t.curriculum_id)),o=t.steps.findIndex(e=>"done"===e.state||"in"===e.state),s=t.steps.map(e=>"done"===e.state||"in"===e.state).lastIndexOf(!0),n=Math.max(0,o),u=Math.min(r.length-1,s+1);c.push(a(t.name,r.slice(n,u+1).join(chalk.gray(" โ†’ "))))}const l=e.tokens.reduce((e,t)=>e+t.contests.passed,0),d=e.tokens.reduce((e,t)=>e+t.contests.total,0),h=e.tokens.reduce((e,t)=>e+t.contests.carried,0);d>0&&c.push(a("Checkpoints",chalk.white(`${l} / ${d} passed`)+(h>0?chalk.gray(` ยท ${h} ${i("โœ…โ†—","carried")}`):"")));const f=e.medals;if(f.gold+f.silver+f.bronze>0&&c.push(a("Medals",chalk.white(o?`${f.gold} gold ยท ${f.silver} silver ยท ${f.bronze} bronze`:`${f.gold} ๐Ÿฅ‡ ${f.silver} ๐Ÿฅˆ ${f.bronze} ๐Ÿฅ‰`))),e.focus.sessions>0){const t=Math.floor(e.focus.total_min/60),r=e.focus.total_min%60;c.push(a("Focus",chalk.white(`${e.focus.sessions} sessions ยท ${t>0?`${t}h `:""}${r}m`)))}e.replies_unread>0&&c.push(a("Replies",chalk.bold.cyan(`${e.replies_unread} new`)+chalk.gray(" ยท open a course and type r")));const y=e.tokens.map(e=>e.last_seen).filter(Boolean).sort().pop()??null;return y&&c.push(a("Last seen",chalk.white(function(e){if(!e)return"";const t=new Date(e);if(Number.isNaN(t.getTime()))return"";const r=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime(),o=Math.round((r(new Date)-r(t))/864e5);return o<=0?"today":1===o?"yesterday":o<30?`${o} days ago`:"a while back"}(y)))),c.push(chalk.cyan(n(s))),c.push(...doorMenuLines(e,r)),c}export function doorMenuLines(e,t){const r="T0"===a().tier,o=t??e?.tokens.filter(e=>e.credits?.completed).length??0,s=(e,t,o)=>chalk.white(" "+(r?" ":`${e} `))+chalk.bold.green(t.padEnd(14))+chalk.gray(o),n=[];return n.push(s("๐Ÿ“–","story",o?`all your stories ยท ${o} finished ยท story <n> for one course`:"all your course stories ยท story <n> for one course")),n.push(s("๐Ÿ‘ค","me","profile ยท ladders ยท medals ยท replies")),n.push(s("โฑ","focus 30","a focus session โ€” any course you open counts")),n.push(s("๐Ÿ“œ","certificate",o?`${o} track${1===o?"":"s"} finished โ€” certificates coming`:"none yet โ€” finish a track first")),n.push(chalk.gray(" ")+chalk.bold.green("c")+chalk.gray(" continue ยท paste a token ยท Enter to go back")),n}export function certificateLines(e,t){const r="T0"===a().tier,o=r?"":"๐Ÿ“œ ",s=e?.tokens.filter(e=>e.credits?.completed)??[],n=[];if(0===s.length)n.push(chalk.bold.white(` ${o}`+(t?"่ฟ˜ๆฒกๆœ‰่ฏไนฆใ€‚":"No certificate yet."))),n.push(chalk.gray(t?" ่ฏไนฆ้š้€šๅ…ณ่€Œๆฅ โ€” ่‡ชๆต‹ๅ…จ็ญ”ใ€็ปƒไน ๅ…จ ACใ€ๆฃ€ๆŸฅ็‚นๅ…จ่ฟ‡็บฟใ€‚":" Certificates come with finished tracks โ€” every check answered, every practice AC, every checkpoint passed.")),n.push(chalk.gray(" ")+chalk.bold.green("story")+chalk.gray(t?" ็œ‹ๆฏ้—จ่ฏพ็ฆป้€šๅ…ณ่ฟ˜ๅทฎไป€ไนˆใ€‚":" shows how far each course is."));else{n.push(chalk.bold.white(` ${o}`+(t?`ๅทฒ้€šๅ…ณ ${s.length} ้—จ โ€” ่ฏไนฆ PDF ๅˆถไฝœไธญ,่ฎฐๅฝ•ๅทฒๆฐธไน…ไฟๅญ˜ใ€‚`:`${s.length} track${1===s.length?"":"s"} finished โ€” certificate PDFs are coming; your record is already saved.`)));for(const e of s){const t=e.credits?.completed_at?new Date(e.credits.completed_at).toLocaleDateString("en-AU",{day:"numeric",month:"short",year:"numeric"}):"";n.push(chalk.gray(" ")+chalk.green(r?"[done] ":"๐Ÿ ")+chalk.white(e.curriculum_id)+chalk.gray(t?` ยท ${t}`:"")+chalk.gray(` ยท story ${e.curriculum_id}`))}}return n}export function doorWelcomeLines(e,t=!1){const{ascii:r,rule:o,center:s}=u(e),n=[];n.push(chalk.cyan(s(o)));const a=r?">":"โ–ถ",i=r?"-":"โ”€";return n.push(chalk.gray(s(`1970 ${i.repeat(3)} algorithms ${i.repeat(8)} 2022 ${i.repeat(3)} AI agents ${i.repeat(3)} you ${a}`))),n.push(chalk.gray(s('"learn to code" "learn to command" '))),n.push(chalk.cyan(s(o))),t?n.push(chalk.gray(" Offline right now โ€” paste your token to continue where you left off.")):(n.push(chalk.gray(" Paste your team token to begin โ€” then these open up:")),n.push(...doorMenuLines(null).slice(0,4))),n}
1
+ import{existsSync as e,readFileSync as t,writeFileSync as s}from"node:fs";import{join as o}from"node:path";import chalk from"chalk";import r from"string-width";import{getIcoaDir as n}from"./config.js";import{detectCaps as a}from"./render-card.js";import{fetchLearnProfile as i}from"./learn-profile.js";const c=()=>o(n(),"profile-cache.json");export async function fetchProfileCached(o){const r=o.toUpperCase();let n={};try{if(e(c())){const e=JSON.parse(t(c(),"utf8"));e&&"object"==typeof e&&!("token"in e)&&(n=e);const s=n[r];if(s&&"number"==typeof s.ts&&Date.now()-s.ts<6e5&&s.profile)return s.profile}}catch{}const a=await i(r,"me");if("ok"!==a.kind)return null;try{n[r]={ts:Date.now(),profile:a.profile},s(c(),JSON.stringify(n))}catch{}return a.profile}export async function fetchProfilesForLocalTokens(e){const t=new Set,s=[];for(const o of e){const e=o.toUpperCase();if(t.has(e)||!/^[A-Z]{2}[A-Z0-9]{8}$/.test(e)||/DEMO01$/.test(e))continue;if(t.add(e),t.size>6)break;const r=await fetchProfileCached(e);r&&s.push(r)}return s}export function dropProfileCache(){try{s(c(),"{}")}catch{}}function u(e){const t=Math.max(48,Math.min(e,72)),s="T0"===a().tier,o=(s?"=":"โ”").repeat(Math.min(34,t-8)),n=Math.min(28,t-28);return{W:t,ascii:s,rule:o,center:e=>" ".repeat(Math.max(0,Math.floor((t-r(e))/2)))+e,row:(e,t)=>chalk.gray(` ${e} ${".".repeat(Math.max(2,n-r(e)))} `)+t}}export function doorStoryLines(e,t,s){const{ascii:o,rule:r,center:n,row:a}=u(t),i=(e,t)=>o?t:e,c=[];c.push(chalk.cyan(n(r))),c.push(chalk.gray(n("your story so far"))),c.push(chalk.cyan(n(r)));const p=[];e.streak_days>0?p.push(`${i("๐Ÿ”ฅ","streak")} ${e.streak_days}-day streak`):p.push("one card today starts a streak"),e.active_days>0&&p.push(`${e.active_days} active days`),e.linked>0&&p.push(`${i("๐Ÿ”—","linked")} ${e.linked+1} tokens`),c.push(a("Tonight",chalk.white(p.join(" ยท "))));for(const t of e.ladders){let e=!1;const s=t.steps.map(t=>"done"===t.state?(e=!0,chalk.green(`${t.curriculum_id} ${i("๐Ÿ","done")}`)):"in"===t.state?(e=!0,chalk.bold.white(`${t.curriculum_id} ${t.cards_done}/${t.total_cards}`)):e?chalk.gray(`${t.curriculum_id} (next)`):chalk.gray(t.curriculum_id)),o=t.steps.findIndex(e=>"done"===e.state||"in"===e.state),r=t.steps.map(e=>"done"===e.state||"in"===e.state).lastIndexOf(!0),n=Math.max(0,o),u=Math.min(s.length-1,r+1);c.push(a(t.name,s.slice(n,u+1).join(chalk.gray(" โ†’ "))))}const h=e.tokens.reduce((e,t)=>e+t.contests.passed,0),l=e.tokens.reduce((e,t)=>e+t.contests.total,0),d=e.tokens.reduce((e,t)=>e+t.contests.carried,0);l>0&&c.push(a("Checkpoints",chalk.white(`${h} / ${l} passed`)+(d>0?chalk.gray(` ยท ${d} ${i("โœ…โ†—","carried")}`):"")));const f=e.medals;if(f.gold+f.silver+f.bronze>0&&c.push(a("Medals",chalk.white(o?`${f.gold} gold ยท ${f.silver} silver ยท ${f.bronze} bronze`:`${f.gold} ๐Ÿฅ‡ ${f.silver} ๐Ÿฅˆ ${f.bronze} ๐Ÿฅ‰`))),e.focus.sessions>0){const t=Math.floor(e.focus.total_min/60),s=e.focus.total_min%60;c.push(a("Focus",chalk.white(`${e.focus.sessions} sessions ยท ${t>0?`${t}h `:""}${s}m`)))}e.replies_unread>0&&c.push(a("Replies",chalk.bold.cyan(`${e.replies_unread} new`)+chalk.gray(" ยท open a course and type r")));const y=e.tokens.map(e=>e.last_seen).filter(Boolean).sort().pop()??null;return y&&c.push(a("Last seen",chalk.white(function(e){if(!e)return"";const t=new Date(e);if(Number.isNaN(t.getTime()))return"";const s=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime(),o=Math.round((s(new Date)-s(t))/864e5);return o<=0?"today":1===o?"yesterday":o<30?`${o} days ago`:"a while back"}(y)))),c.push(chalk.cyan(n(r))),c.push(...doorMenuLines(e,s)),c}export function doorMenuLines(e,t){const s="T0"===a().tier,o=t??e?.tokens.filter(e=>e.credits?.completed).length??0,r=(e,t,o)=>chalk.white(" "+(s?" ":`${e} `))+chalk.bold.green(t.padEnd(14))+chalk.gray(o),n=[];return n.push(r("๐Ÿ“–","story",o?`all your stories ยท ${o} finished ยท story <n> for one course`:"all your course stories ยท story <n> for one course")),n.push(r("๐Ÿ‘ค","me","profile ยท ladders ยท medals ยท replies")),n.push(r("โฑ","focus 30","a focus session โ€” any course you open counts")),n.push(r("โฑ","focus log",e&&e.focus.sessions>0?`your focus sessions ยท ${e.focus.sessions} so far ยท report per session`:"your focus sessions โ€” the report of each one, newest first")),n.push(r("๐Ÿ“œ","certificate",o?`${o} track${1===o?"":"s"} finished โ€” certificates coming`:"none yet โ€” finish a track first")),n.push(chalk.gray(" ")+chalk.bold.green("c")+chalk.gray(" continue ยท paste a token ยท Enter to go back")),n}export function certificateLines(e,t){const s="T0"===a().tier,o=s?"":"๐Ÿ“œ ",r=e?.tokens.filter(e=>e.credits?.completed)??[],n=[];if(0===r.length)n.push(chalk.bold.white(` ${o}`+(t?"่ฟ˜ๆฒกๆœ‰่ฏไนฆใ€‚":"No certificate yet."))),n.push(chalk.gray(t?" ่ฏไนฆ้š้€šๅ…ณ่€Œๆฅ โ€” ่‡ชๆต‹ๅ…จ็ญ”ใ€็ปƒไน ๅ…จ ACใ€ๆฃ€ๆŸฅ็‚นๅ…จ่ฟ‡็บฟใ€‚":" Certificates come with finished tracks โ€” every check answered, every practice AC, every checkpoint passed.")),n.push(chalk.gray(" ")+chalk.bold.green("story")+chalk.gray(t?" ็œ‹ๆฏ้—จ่ฏพ็ฆป้€šๅ…ณ่ฟ˜ๅทฎไป€ไนˆใ€‚":" shows how far each course is."));else{n.push(chalk.bold.white(` ${o}`+(t?`ๅทฒ้€šๅ…ณ ${r.length} ้—จ โ€” ่ฏไนฆ PDF ๅˆถไฝœไธญ,่ฎฐๅฝ•ๅทฒๆฐธไน…ไฟๅญ˜ใ€‚`:`${r.length} track${1===r.length?"":"s"} finished โ€” certificate PDFs are coming; your record is already saved.`)));for(const e of r){const t=e.credits?.completed_at?new Date(e.credits.completed_at).toLocaleDateString("en-AU",{day:"numeric",month:"short",year:"numeric"}):"";n.push(chalk.gray(" ")+chalk.green(s?"[done] ":"๐Ÿ ")+chalk.white(e.curriculum_id)+chalk.gray(t?` ยท ${t}`:"")+chalk.gray(` ยท story ${e.curriculum_id}`))}}return n}export function doorWelcomeLines(e,t=!1){const{ascii:s,rule:o,center:r}=u(e),n=[];n.push(chalk.cyan(r(o)));const a=s?">":"โ–ถ",i=s?"-":"โ”€";return n.push(chalk.gray(r(`1970 ${i.repeat(3)} algorithms ${i.repeat(8)} 2022 ${i.repeat(3)} AI agents ${i.repeat(3)} you ${a}`))),n.push(chalk.gray(r('"learn to code" "learn to command" '))),n.push(chalk.cyan(r(o))),t?n.push(chalk.gray(" Offline right now โ€” paste your token to continue where you left off.")):(n.push(chalk.gray(" Paste your team token to begin โ€” then these open up:")),n.push(...doorMenuLines(null).slice(0,4))),n}
@@ -0,0 +1 @@
1
+ import chalk from"chalk";import{httpFetch as e}from"./http.js";import{LEARN_SERVER as t}from"./learn-curricula.js";import{learnW as s}from"./learn-render.js";import{getCliVersion as r}from"./version.js";export async function fetchFocusLog(s){if(s.toUpperCase().endsWith("DEMO01"))return{kind:"demo"};try{const a=await e(`${t.replace(/\/$/,"")}/api/icoa/learn/focus/log`,{method:"POST",headers:{"Content-Type":"application/json","X-ICOA-Client":r()},body:JSON.stringify({token:s.toUpperCase()}),signal:AbortSignal.timeout(15e3)}),o=await a.json();return o.success&&o.data&&Array.isArray(o.data.sessions)?{kind:"ok",log:o.data}:"demo"===o.code?{kind:"demo"}:{kind:"error",message:o.message||`HTTP ${a.status}`}}catch{return{kind:"offline"}}}export const FOCUS_LOG_RE=/^\/?(?:focus|timer)\s+(?:log|logs|history|list|records?)$|^\/?focus-?log$/i;function a(e){const t=Math.round(e/6e4);return t>=60?`${Math.floor(t/60)}h ${t%60}m`:`${t}m`}export function renderFocusLog(e,t,r,o){const n=r?"":"โฑ ",i=s(),c=[];return c.push(""),0===e.sessions.length?(c.push(chalk.bold.white(` ${n}`+(t?"่ฟ˜ๆฒกๆœ‰ไธ“ๆณจ่ฎฐๅฝ•ใ€‚":"No focus sessions yet."))),c.push(chalk.gray(t?" ่พ“ focus 30(15โ€“60 ๅˆ†้’Ÿ)ๅผ€ๅง‹ไธ€ๆฎต;ๆ‰“ๅผ€ไปปไฝ•่ฏพ็จ‹้ƒฝ็ฎ—;็ป“ๆŸๆ—ถๆŠฅๅ‘Šไผš่ฎฐๅœจ่ฟ™้‡Œใ€‚":" Type focus 30 (15โ€“60 min) to start one; any course you open counts; the report lands here.")),c.push(""),c.push(chalk.gray(` ${o}`)),c):(c.push(chalk.bold.white(` ${n}`+(t?"ไธ“ๆณจ่ฎฐๅฝ•":"Focus log"))+chalk.gray(t?` ยท ${e.total_sessions} ๆฎต ยท ๅ…ฑ ${a(6e4*e.total_min)} ยท ๆœ€่ฟ‘ๅœจๅ‰`:` ยท ${e.total_sessions} session${1===e.total_sessions?"":"s"} ยท ${a(6e4*e.total_min)} total ยท newest first`)),c.push(chalk.gray(` ${"โ”€".repeat(Math.max(24,i-2))}`)),e.sessions.forEach((s,r)=>{const o=e.sessions.length-r,n=`${s.planned_min}m`,i=a(s.actual_ms),d=s.aborted?chalk.yellow(t?" ไธญๆ–ญ":" aborted"):s.early?chalk.gray(t?` ๆๅ‰็ป“ๆŸ(${i}/${n})`:` ended early (${i}/${n})`):chalk.green(` ${i}`),u=s.ratings.filter(e=>null!=e).length?chalk.gray((t?" ยท ่‡ช่ฏ„ ":" ยท self-rating ")+s.ratings.map(e=>function(e,t){return null==e?"โ€“":t?["ๅทฎ","ไธ€่ˆฌ","ๅฅฝ"][e]:["bad","ok","good"][e]}(e,t)).join(" / ")):"";c.push(chalk.white(` ${String(o).padStart(2)}. `)+chalk.bold.white(function(e,t){const s=new Date(e);if(Number.isNaN(s.getTime()))return e.slice(0,16);const r=e=>String(e).padStart(2,"0"),a=`${s.getFullYear()}-${r(s.getMonth()+1)}-${r(s.getDate())}`,o=`${r(s.getHours())}:${r(s.getMinutes())}`,n=e=>new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime(),i=Math.round((n(new Date)-n(s))/864e5);return`${i<=0?t?"ไปŠๅคฉ":"today":1===i?t?"ๆ˜จๅคฉ":"yesterday":a} ${o}`}(s.started_at,t))+d+u);for(const e of s.segments){const s=null!=e.card_from&&null!=e.card_to?t?`ๅก ${e.card_from}โ†’${e.card_to}(${e.cards_viewed} ๅผ )`:`cards ${e.card_from}โ†’${e.card_to} (${e.cards_viewed})`:t?`${e.cards_viewed} ๅผ ๅก`:`${e.cards_viewed} cards`,r=e.checks_answered?` ยท ${e.checks_correct}/${e.checks_answered} โœ“`:"",a=e.practice_ac?t?` ยท ็ปƒไน  AC ${e.practice_ac}`:` ยท practice AC ${e.practice_ac}`:"",o=e.median_card_ms?t?` ยท ๆฏๅกไธญไฝ ${Math.round(e.median_card_ms/1e3)}s`:` ยท median ${Math.round(e.median_card_ms/1e3)}s/card`:"",n=e.cards_under_3s?chalk.yellow(t?` ยท 3 ็ง’ๅ†…็ฟป่ฟ‡ ${e.cards_under_3s}`:` ยท ${e.cards_under_3s} under 3s`):"",i=e.ai_questions?t?` ยท AI ๆ้—ฎ ${e.ai_questions}`:` ยท ${e.ai_questions} AI q`:"";c.push(chalk.gray(" ")+chalk.cyan(e.curriculum_id)+chalk.gray(` ${s}${r}${a}${o}`)+n+chalk.gray(i))}}),c.push(chalk.gray(` ${"โ”€".repeat(Math.max(24,i-2))}`)),c.push(chalk.gray((t?" ๅ†ๆฅไธ€ๆฎต:":" Another one: ")+chalk.bold.green("focus 30")+chalk.gray(t?"(15โ€“60)ยท ":" (15โ€“60) ยท ")+o)),c)}
package/dist/repl.js CHANGED
@@ -1 +1 @@
1
- import{createInterface as o}from"node:readline";import{spawn as e,execSync as t}from"node:child_process";import chalk from"chalk";import{appendExitLog as n}from"./lib/exit-log.js";import{dispatchable as l,helpRows as a,shortcutFor as s,subcommandsOf as r,surface as i}from"./lib/commands.js";import{distance as c}from"fastest-levenshtein";import{isConnected as g,getConfig as y,saveConfig as m}from"./lib/config.js";import{ensureLangCache as d}from"./lib/translations-fetcher.js";import{loadUiPack as u}from"./lib/i18n.js";import{isActivated as p,activateToken as h,isFreeCommand as f,isDeviceMatch as w,recordExit as b,recordResume as k,isFirstRunOrUpgrade as x,markVersionSeen as v}from"./lib/access.js";import{setReplMode as C}from"./lib/ui.js";import{returnToMainMenu as $,printMenuHint as A,menuHintInline as I,registerRealExit as T}from"./lib/menu-nav.js";import{setMainRl as S}from"./lib/main-rl.js";import{shellSplit as E}from"./lib/shell-split.js";import{isChatActive as j,handleChatMessage as O}from"./commands/ai4ctf.js";import{renderToolMan as N}from"./lib/tool-man.js";import{isCtf4aiActive as L,handleCtf4aiMessage as D}from"./commands/ctf4ai-demo.js";import{isCtf4VlaActive as P,handleCtf4VlaMessage as _}from"./commands/ctf4vla.js";import{isDemo2Active as M}from"./commands/demo2.js";import{isSprintActive as F}from"./commands/sprint.js";import{isCardDeckActive as U}from"./lib/card-engine.js";import{hasAnySimHistory as R,lastArmAt as q,lastBundledAt as W,lastSimAt as B}from"./lib/sim-cooldown.js";import{getExamState as Z,getRealExamState as Y,getDemoState as X,practicalChatCommand as Q}from"./lib/exam-state.js";import{resolveResumePoint as z}from"./lib/resume.js";import{buildStatusLine as H}from"./lib/statusline.js";import{startBgTask as J,startAsyncTask as V,listBgTasks as G,getBgTask as K,drainCompleted as oo,killAllBgTasks as eo,runningCount as to}from"./lib/bgtasks.js";import{computeStart as no,renderStart as lo}from"./commands/challenge.js";import{addDraft as ao,listDrafts as so,removeDraft as ro,clearDrafts as io}from"./lib/drafts.js";import{resetTerminalTheme as co}from"./lib/theme.js";import{ensureSandbox as go,runInSandbox as yo,isDockerAvailable as mo}from"./lib/sandbox.js";import{checkShellRisk as uo,logShellAudit as po,getActiveCwd as ho}from"./lib/exam-sandbox.js";import{logCommand as fo}from"./lib/logger.js";import{startLogSync as wo,stopLogSync as bo}from"./lib/log-sync.js";import{installInputDynamics as ko,uninstallInputDynamics as xo,stripTerminalMarkers as vo,rearmFocusMode as Co}from"./lib/input-dynamics.js";import{startBroadcastPoll as $o,stopBroadcastPoll as Ao,showBroadcast as Io,isCompetitionJoined as To,isMelCompetition as So,isLeaderAccount as Eo,isLeaderSession as jo,fetchPublicScoreboard as Oo,isCommsActive as No}from"./lib/comms.js";import{enterMemoScreen as Lo,enterJuryScreen as Do}from"./commands/comms.js";import{existsSync as Po,mkdirSync as _o,readFileSync as Mo,writeFileSync as Fo}from"node:fs";import{join as Uo}from"node:path";import{homedir as Ro}from"node:os";const qo="# ICOA exam interactive startup โ€” auto-loaded by PYTHONSTARTUP\nimport base64, struct, hashlib, re, json, os, sys, binascii\ntry: import requests\nexcept ImportError: pass\ntry: from Crypto.Cipher import AES\nexcept ImportError: pass\ntry: from Crypto.Util.Padding import pad, unpad\nexcept ImportError: pass\ntry: from pwn import xor, p32, u32, p64, u64\nexcept ImportError: pass\ntry: import bs4\nexcept ImportError: pass\ntry: import numpy as np\nexcept ImportError: pass\ntry: from PIL import Image\nexcept ImportError: pass\n",Wo=Date.now();function Bo(){return So()?chalk.yellow("icoa 2026> "):Y()?chalk.cyan("icoa exam> "):function(){const o=X();return!(!o||"demo-free"!==o.session?.examId)&&new Date(o.session.startedAt||0).getTime()>=Wo}()?chalk.yellow("icoa demo> "):chalk.green("icoa> ")}const Zo=Uo(Ro(),"icoa-workspace"),Yo=new Set(["sudo","su","doas","pkexec","brew","apt","apt-get","yum","choco","npm","npx","pip","pip3","shutdown","reboot","halt","mkfs","fdisk","dd","iptables","ufw"]),Xo="__REPL_NO_EXIT__",Qo="2.5.1",zo=i();export function nearestCommand(o,e=2){const t=o.trim().toLowerCase();if(!t)return null;let n={word:"",dist:Number.POSITIVE_INFINITY};for(const o of zo){const e=c(t,o);e<n.dist&&(n={word:o,dist:e})}return n.dist>0&&n.dist<=e?n.word:null}const Ho=new Set(["answer","demo","demo-retry","help","list","mark","more-help","nations","next","prev","q","reset","result","review","setup","start","submit","token","unmark","status","time"]);function Jo(o){const e=o.replace(/^\s+/,"");if(/^\/\S*$/.test(e)){const o=e.slice(1).toLowerCase();return[zo.filter(e=>e.startsWith(o)).map(o=>`/${o}`),e]}const t=e.split(/\s+/);if(t.length<=1){const o=(t[0]??"").toLowerCase();return[zo.filter(e=>e.startsWith(o)).slice(),o]}if(2===t.length){const o=r(t[0].toLowerCase());if(o){const e=t[1].toLowerCase();return[o.filter(o=>o.startsWith(e)).slice(),e]}}return[[],o]}async function Vo(o){const e=z();if(!e)return null;const t=process.exit;process.exit=()=>{throw new Error(Xo)};try{await o.parseAsync(["node","icoa",...e.command])}catch(o){if(!(o instanceof Error&&o.message===Xo))throw o}finally{process.exit=t}return e}function Go(){console.log(),console.log(` ${chalk.cyan.bold("๐ŸŽฏ ICOA 2026 ยท National Selection")}`),console.log(),console.log(" "+chalk.bold.cyan("learn ")+chalk.white("ACxxxxxxxx")+chalk.gray(" โ†’ ai4ctf-12 (AI as your CTF teammate)")),console.log(" "+chalk.bold.cyan("learn ")+chalk.white("CAxxxxxxxx")+chalk.gray(" โ†’ ctf4ai-12 (red-team software AI)")),console.log(" "+chalk.bold.cyan("learn ")+chalk.white("EAxxxxxxxx")+chalk.gray(" โ†’ ctf4eai-12 (red-team embodied AI)")),console.log(" "+chalk.bold.cyan("exam ")+chalk.white("<CC>xxxxxxxx")+chalk.gray(" โ†’ Paper A/B/C/D/E (country exam token)")),console.log(" "+chalk.bold.cyan("demo")+chalk.gray(" โ†’ free practice")),console.log(" "+chalk.bold.cyan("lang")+chalk.white(" es")+chalk.gray(" โ†’ switch language")),console.log(" "+chalk.gray("help ยท menu ยท quit")),console.log()}export async function startRepl(e,a){process.env.ICOA_INSIDE_REPL="1";let s=!1;if(So()){const o=y().joinedAt,e=o=>new Intl.DateTimeFormat("en-CA",{timeZone:"Australia/Sydney",year:"numeric",month:"2-digit",day:"2-digit"}).format(o);o&&e(new Date(o))===e(new Date)||(m({ctfdUrl:"",token:"",sessionCookie:"",userId:null,userName:"",teamId:null,country:"",joinedAt:""}),s=!0)}const r=y(),i=g(),c=process.exit.bind(process);T(c);const E=p();if(r.language&&"en"!==r.language&&(await d(r.language,{silent:!0}),u(r.language)),r.demoCleanedForVersion!==Qo){try{const{existsSync:o,unlinkSync:e}=await import("node:fs"),{join:t}=await import("node:path"),{getIcoaDir:n}=await import("./lib/config.js"),l=t(n(),"demo-state.json");o(l)&&e(l)}catch{}m({demoCleanedForVersion:Qo})}const{select:X,confirm:Co}=await import("@inquirer/prompts"),Wo=r.mode||"",ee=""===Wo?"instant":["instant","learn","selection","olympiad"].includes(Wo)?Wo:"selection",te=[{name:` ${chalk.bold("โšก Try ICOA in 30 seconds")} ${chalk.gray("โ€”")} ${chalk.gray("watch ยท no token needed")}`,value:"instant"},{name:` ${chalk.bold("๐Ÿง  Learn")} ${chalk.gray("โ€”")} ${chalk.gray("team token ยท skill up")}`,value:"learn"},{name:` ${chalk.bold("๐ŸŽฏ National Selection")} ${chalk.gray("โ€”")} ${chalk.gray("country exam token ยท aim for finals")}`,value:"selection"},{name:` ${chalk.bold("๐Ÿ† International Olympiad")} ${chalk.gray("โ€”")} ${chalk.gray("finals stage ยท Sydney 2026 ยท full sandbox")}`,value:"olympiad"},{name:` ${chalk.gray("โ„น๏ธ About ICOA")} ${chalk.gray("ยท")} ${chalk.gray("what this is ยท how to join")}`,value:"about"}];""===Wo&&(console.log(chalk.green(" ๐Ÿ‘‹ First time here? ")+chalk.white("Just press ")+chalk.bold.cyan("Enter")+chalk.white(" โ€” youโ€™ll see ICOA in 30 seconds, no signup needed.")),console.log()),console.log(chalk.gray(" Type ")+chalk.bold.cyan("menu")+chalk.gray(" from anywhere to return here.")),console.log();let ne="";for(;!ne;){let o;const e=process.env.ICOA_TEST_BOOT_MODE;if(e&&["instant","learn","selection","olympiad"].includes(e))o=e;else try{o=await X({message:"Mode",choices:te,default:ee||"instant"})}catch(o){throw o instanceof Error&&"ExitPromptError"===o.name&&(console.log(),console.log(chalk.gray(" Goodbye.")),process.exit(0)),o}if("about"!==o)ne=o;else{console.clear(),console.log(),console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log(chalk.bold.yellow(" ICOA")+chalk.white(" โ€” AI-Native CLI OS for Cyber & AI Security")),console.log(chalk.gray(" Olympiad & Competition ยท K-12 to University")),console.log(chalk.cyan(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(),console.log(chalk.bold.white(" What Makes ICOA Different")),console.log(chalk.gray(" ยท AI-native AI teammate, AI adversary, AI translation")),console.log(chalk.gray(" ยท CLI OS Complete competition environment in terminal")),console.log(chalk.gray(" ยท 110 tools pwntools, z3, gdb, nmap, sleuthkit... pre-configured")),console.log(chalk.gray(" ยท Global scale 15,000+ concurrent exams ยท 20+ languages")),console.log(),console.log(chalk.bold.white(" Three Frontiers of AI Security")),console.log(` ${chalk.green.bold("AI4CTF")}${chalk.gray(" AI as teammate โ€” 5 CTF disciplines, 5-hour endurance round")}`),console.log(` ${chalk.red.bold("CTF4AI")}${chalk.gray(" AI as target โ€” the AI system itself is the objective")}`),console.log(` ${chalk.cyan.bold("CTF4EAI")}${chalk.gray(" Embodied-AI Arena โ€” probe robot policies in live simulation")}`),console.log(),console.log(chalk.bold.white(" First Edition โ€” Sydney 2026 ")+chalk.green.bold("โœ“ held")),console.log(chalk.gray(" ยท Jun 27 - Jul 2, 2026 ยท University of Technology Sydney")),console.log(chalk.gray(" ยท 65 competitors ยท 20 countries & regions (10 on-site, 10 remote)")),console.log(chalk.gray(" ยท 36 awards โ€” 6 Gold ยท 11 Silver ยท 17 Bronze ยท 2 Honorable Mentions")),console.log(chalk.gray(" ยท Champion: Oleg Uteshev ยท Embodied-AI Arena Gold: Kingsley Lim (AU)")),console.log(chalk.gray(" ยท Founding Charter signed โ€” ICOA is now a permanent institution")),console.log(),console.log(chalk.bold.white(" Next: ICOA 2027")+chalk.gray(" โ€” 20 more countries already accredited")),console.log(),console.log(chalk.bold.white(" Organized by")+chalk.gray(" ASRA (Australia) ยท ICO Foundation Inc")),console.log(chalk.bold.white(" Contact ")+chalk.cyan(" australia@icoa2026.au ยท accreditation@icoa2026.au")),console.log(chalk.bold.white(" Website ")+chalk.cyan.underline(" https://icoa2026.au")+chalk.gray(" ยท press: ")+chalk.cyan.underline("https://icoa2026.au/press/")),console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log();try{const{input:o}=await import("@inquirer/prompts"),e=()=>o({message:chalk.gray("Press Enter to return..."),theme:{prefix:"",style:{message:o=>o}}}),t=Date.now();await e(),Date.now()-t<200&&await e()}catch{}console.clear()}}if("olympiad"===ne&&"olympiad"!==ee){console.log(),console.log(chalk.yellow(" This mode will download ~500MB of CTF tools and AI models."));let o=!0;try{o=await Co({message:"Continue?",default:!0})}catch(e){if(!(e instanceof Error&&"ExitPromptError"===e.name))throw e;o=!1}o||(ne="selection",console.log(chalk.gray(" Switched to National Selection mode.")))}if(ne!==ee&&m({mode:ne}),console.log(),"olympiad"===ne&&x(Qo)){v(Qo),console.log(chalk.gray(" Checking competition environment..."));const{execSync:o}=await import("node:child_process"),e=[{name:"pwntools",cmd:'python3 -c "import pwn"'},{name:"z3-solver",cmd:'python3 -c "import z3"'},{name:"numpy",cmd:'python3 -c "import numpy"'},{name:"requests",cmd:'python3 -c "import requests"'}];let t=0;for(const n of e)try{o(n.cmd,{stdio:"ignore"})}catch{t++}t>0?(console.log(chalk.yellow(` ${t} core competition libraries missing.`)),console.log(chalk.gray(" Run ")+chalk.white("env setup")+chalk.gray(" when you are ready to install them.")),console.log()):(console.log(chalk.green(" All core libraries ready.")),console.log())}if(a){const o=k();if(o){const e=Math.floor(o.awaySeconds/60),t=o.awaySeconds%60;console.log(chalk.yellow(` Session resumed. Away: ${e}m ${t}s | Total exits: ${o.exitCount}`)),console.log()}}if("selection"===ne)console.log(chalk.gray(" โ”€โ”€โ”€ exam hall ยท 90 min per paper once started ยท no pause โ”€โ”€โ”€")),console.log(),Go();else if("embodied"===ne)!function(){console.log(chalk.cyan.bold(" [๐Ÿค– ctf4eai โ€” Embodied AI Security]")),console.log(),console.log(chalk.bold.cyan(" CTF4EAI")+chalk.gray(" โ€” ICOA 2026's ")+chalk.bold.white("Pioneer Round")),console.log(chalk.gray(" an independent parallel track alongside the scored main events: ")+chalk.green("AI4CTF")+chalk.gray(" (Day 1) and ")+chalk.red("CTF4AI")+chalk.gray(" (Day 2)")),console.log(),console.log(chalk.white(" Embodied AI is at its ImageNet moment.")),console.log(chalk.gray(" VLA models, MuJoCo physics, real robot arms.")),console.log(chalk.gray(" Real models, real physics, real attack surfaces.")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€"));const o=W()>0||B()>0,e=q()>0,t=R();o&&e?console.log(chalk.bold.yellow(" Next up: ")+chalk.bold.cyan("โ‘ข demo2")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ฃ learn LEARNDEMO01")+chalk.gray(" (sim โœ“ ยท sim arm โœ“)")):t?console.log(chalk.bold.yellow(" Next up: ")+(e?chalk.bold.cyan("โ‘  sim")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ข demo2"):chalk.bold.cyan("โ‘ก sim arm")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ข demo2"))+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ฃ learn LEARNDEMO01")):console.log(chalk.bold.yellow(" First time? Try in order: ")+chalk.bold.cyan("โ‘  sim")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ก sim arm")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ข demo2")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ฃ learn LEARNDEMO01")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.bold.green(" sim")+chalk.gray(" ")+chalk.bold.cyan("โ‘ ")+chalk.gray(" ")+chalk.bold.yellow("โ˜… INSTANT")+chalk.gray(" โ€” 9-robot group dance, no wait, no setup")),console.log(chalk.bold.green(" sim arm")+chalk.gray(" ")+chalk.bold.cyan("โ‘ก")+chalk.gray(" interactive 6-DOF arm sandbox โ€” type joint values, watch")),console.log(chalk.bold.green(" demo2")+chalk.gray(" ")+chalk.bold.cyan("โ‘ข")+chalk.gray(" ~8 min interactive intro + live MuJoCo sim")),console.log(chalk.bold.green(" learn LEARNDEMO01")+chalk.gray(" ")+chalk.bold.cyan("โ‘ฃ")+chalk.gray(" free 11-card intro (paste this command as-is)")),console.log(chalk.bold.green(" learn ")+chalk.bold.yellow("EA")+chalk.gray(" + 8 chars full 96 / 360 curriculum (team-issued)")),console.log(chalk.bold.green(" exam ")+chalk.bold.yellow("PDxxxxxxxx")+chalk.gray(" Paper D (CTF4EAI) โ€” national selection contestants")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(),console.log(chalk.gray(" Three open tiers: ")+chalk.green("free 11")+chalk.gray(" ยท ")+chalk.yellow("registered 100")+chalk.gray(" ยท ")+chalk.bold.magenta("national team 480")+chalk.gray(" (PhD-ready)")),console.log(chalk.gray(" Country team contact: ")+chalk.cyan("australia@icoa2026.au")),console.log(),A(),console.log()}();else if("instant"===ne)console.log(chalk.cyan.bold(" [โšก Try ICOA in 30 seconds โ€” no token needed]")),console.log(),console.log(chalk.gray(" Three free tastes โ€” just type the word and press Enter:")),console.log(),console.log(chalk.bold.green(" demo ")+chalk.gray(" Paper A/B/C taste โ€” 10 MCQs, no timer ")+chalk.bold.cyan("๐ŸŽฏ selection-style")),console.log(chalk.bold.green(" demo2 ")+chalk.gray(" Embodied-AI mini-demo โ€” robots & MuJoCo ")+chalk.bold.yellow("๐Ÿค– hands-on")),console.log(chalk.bold.green(" kaggle")+chalk.gray(" ML practice โ€” train a model, real board ")+chalk.bold.magenta("๐Ÿ“Š data-science")),console.log(),console.log(chalk.gray(" Type ")+chalk.bold.cyan("demo")+chalk.gray(", ")+chalk.bold.cyan("demo2")+chalk.gray(" or ")+chalk.bold.cyan("kaggle")+chalk.gray(" to start ยท ")+chalk.bold.cyan("menu")+chalk.gray(" to go back ยท ")+chalk.bold.cyan("quit")+chalk.gray(" to exit")),console.log(),m({mode:"selection"}),ne="selection";else{if("learn"===ne){console.log(chalk.cyan.bold(" [๐Ÿง  Learn]")),console.log();const o=await(async()=>{try{const o=await import("./lib/learn-state.js");return{sessions:o.listLearnSessions(),listMax:o.CONTINUE_LIST_MAX}}catch{return{sessions:[],listMax:5}}})(),t=o.sessions,l=o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o)?`${o.slice(0,2)}โ€ขโ€ขโ€ขโ€ขโ€ขโ€ข${o.slice(-2)}`:o,a=o=>{const e=new Date(o);if(Number.isNaN(e.getTime()))return"";const t=o=>new Date(o.getFullYear(),o.getMonth(),o.getDate()).getTime(),n=Math.round((t(new Date)-t(e))/864e5);return n<0?"":0===n?"today":1===n?"yesterday":n<30?`${n} days ago`:"a while back"},s=e=>{const n=e?t:t.slice(0,o.listMax),s=o=>Math.max(...n.map(e=>o(e).length)),r=s(o=>o.curriculumId),i=s(o=>`card ${o.currentCard}/${o.totalCards}`),c=s(o=>a(o.lastSeenAt));return n.forEach((o,e)=>{const t=o.token===o.curriculumId?"":` ${l(o.token)}`;console.log(chalk.green(` ${e+1} `)+chalk.bold.white(o.curriculumId.padEnd(r))+chalk.gray(` ${`card ${o.currentCard}/${o.totalCards}`.padEnd(i)} ${a(o.lastSeenAt).padEnd(c)}${t}`))}),n.length};if(1===t.length){const o=t[0],e=a(o.lastSeenAt);console.log(chalk.green(" โ–ธ Continue ")+chalk.bold.white(o.curriculumId)+chalk.gray(` ยท card ${o.currentCard}/${o.totalCards}${e?` ยท ${e}`:""} ยท ${l(o.token)}`)),console.log(chalk.gray(" type ")+chalk.bold.green("c")+chalk.gray(" or ")+chalk.bold.green("continue")+chalk.gray(" to resume ยท Enter to go back")),console.log()}else if(t.length>1){console.log(chalk.green(" โ–ธ Continue"));const o=s(!1);t.length>o&&console.log(chalk.gray(` +${t.length-o} more โ€” type `)+chalk.bold.green("c all")+chalk.gray(" to list them")),console.log(chalk.gray(" type ")+chalk.bold.green("c")+chalk.gray(" to resume 1 ยท ")+chalk.bold.green("c 2")+chalk.gray(" to switch ยท Enter to go back")),console.log()}{const{doorStoryLines:o,doorWelcomeLines:e,fetchProfilesForLocalTokens:n}=await import("./lib/learn-door.js"),{learnW:l}=await import("./lib/learn-render.js");let a=null;if(t.find(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token))){const s=await n(t.map(o=>o.token)),r=s[0]??null,i=new Set(s.flatMap(o=>o.tokens.filter(o=>o.credits?.completed).map(o=>o.curriculum_id))).size;a=r?o(r,l(),i):e(l(),!0)}else a=e(l(),!1);for(const o of a)console.log(o);console.log()}try{const{input:o}=await import("@inquirer/prompts"),{resolveLearnInput:n}=await import("./lib/learn-input.js");console.log(chalk.gray(" Enter a token (or just press Enter to go back).")),console.log();const l=async()=>{try{await o({message:chalk.bold.yellow("Press Enter to return to the menu"),theme:{prefix:"",style:{message:o=>o}}})}catch{}},a=3;for(let r=1;r<=a;r++){const i=await o({message:chalk.bold.cyan("icoa learn>"),theme:{prefix:"",style:{message:o=>o}}}),c=i.trim().toLowerCase();if("ai4ioai"===c||"/ai4ioai"===c){const{runAi4ioaiStandalone:o}=await import("./commands/ai4ioai.js");return await o(),await l(),m({mode:"selection"}),void $()}if(["pandahelpme31","/pandahelpme31","panda help me 31","pandahelpme"].includes(c)){const{runSprint:o}=await import("./commands/sprint.js");return await o(),m({mode:"selection"}),void $()}if("wm"===c||"/wm"===c||c.startsWith("wm ")){const{runWm:o}=await import("./commands/wm.js");return await o(i.trim().split(/\s+/).slice(1).join(" ")||void 0),m({mode:"selection"}),void $()}if("ioailab"===c||"/ioailab"===c){const{runIoailabStandalone:o}=await import("./commands/ioailab.js");return await o(),await l(),m({mode:"selection"}),void $()}if("me"===c||"/me"===c||"profile"===c||"/profile"===c){const o=t.find(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token));if(o){const{fetchLearnProfile:e,renderLearnProfile:t}=await import("./lib/learn-profile.js"),{learnW:n}=await import("./lib/learn-render.js");console.log(chalk.gray(` Loading your profile (${o.token.slice(0,2)}โ€ขโ€ขโ€ขโ€ขโ€ขโ€ข${o.token.slice(-2)})โ€ฆ`));const l=await e(o.token);"ok"===l.kind?t(l.profile,!1,n(),"prompt"):"offline"===l.kind?console.log(chalk.yellow(" Cannot reach the learn server โ€” try me again online.")):console.log(chalk.yellow(` ${"demo"===l.kind?"No profile for a demo token":l.message}`)),console.log()}else console.log(),console.log(chalk.yellow(" No profile yet โ€” open a course with your token first, then type me.")),console.log();r--;continue}const g=c.match(/^\/?(certificate|certificates|cert)(?:\s+(\S+))?$/);if(g){const{certificateLines:e,dropProfileCache:n}=await import("./lib/learn-door.js"),{certifiable:l,certificateIntroLines:a,sameName:s,issueCertificate:i,announceCertificate:c}=await import("./lib/learn-certificate.js"),{fetchProfilesForLocalTokens:y}=await import("./lib/learn-door.js"),m=await y(t.map(o=>o.token)),d=m[0]??null,u=new Set,p=m.flatMap(o=>l(o)).filter(o=>!u.has(o.curriculum_id)&&u.add(o.curriculum_id)),h=(g[2]??"").toLowerCase();console.log();const f=h?p.find(o=>o.curriculum_id.toLowerCase()===h||o.curriculum_id.toLowerCase().startsWith(h)):1===p.length?p[0]:void 0;if(0===p.length||!f&&!h){for(const o of e(d,!1))console.log(o);p.length>1&&console.log(chalk.gray(" type ")+chalk.bold.green("certificate <track>")+chalk.gray(" to issue one.")),console.log(),r--;continue}if(!f){console.log(chalk.yellow(` No finished track matches "${h}". `)+chalk.gray("Finished: "+p.map(o=>o.curriculum_id).join(", "))),console.log(),r--;continue}for(const o of a(f,!1))console.log(o);console.log();const w=async e=>(await o({message:chalk.bold.cyan(e),theme:{prefix:"",style:{message:o=>o}}})).trim(),b=await w("Name on the certificate:");if(!b){console.log(chalk.gray(" Cancelled โ€” nothing issued.")),console.log(),r--;continue}if(!s(b,await w("Type it once more:"))){console.log(chalk.yellow(" The two names differ โ€” nothing issued. Type certificate to try again.")),console.log(),r--;continue}console.log(chalk.gray(" Issuingโ€ฆ (the name is sent once, never stored)")),c(await i(f.token,f.curriculum_id,b),!1),n(),r--;continue}const y=c.match(/^\/?(story|credits)(?:\s+(\S+))?$/);if(y){const{fetchLearnProfile:o}=await import("./lib/learn-profile.js"),{buildCreditLines:e,rollCredits:n,storyListLines:l}=await import("./lib/learn-credits.js"),{learnW:a}=await import("./lib/learn-render.js"),s=t.find(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token));if(console.log(),s){const r=await o(s.token,"credits"===y[1]?"credits":"story");if("ok"!==r.kind)console.log(chalk.yellow(" Cannot reach the learn server โ€” try story again online."));else{const o=(y[2]??"").toLowerCase(),s=r.profile;let i;if(o){const e=Number(o);i=Number.isInteger(e)&&e>=1&&e<=s.tokens.length?s.tokens[e-1]:s.tokens.find(e=>e.curriculum_id.toLowerCase()===o||e.curriculum_id.toLowerCase().startsWith(o))}else"credits"===y[1]&&(i=s.tokens.find(o=>o.credits?.completed));if(i){if(await n(e(i,s,i.curriculum_id,{},!1,a(),!1),()=>!1,180),i.credits?.completed&&!i.credits.credits_rolled_at){const{postCreditsRolled:o}=await import("./lib/learn-profile.js");o(i.token,i.curriculum_id)}}else{o&&console.log(chalk.yellow(` No story for "${o}".`));for(const o of l(s,!1))console.log(o);const e=new Set(s.tokens.map(o=>o.token.toUpperCase())),n=t.filter(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token)&&!e.has(o.token.toUpperCase()));n.length>0&&console.log(chalk.gray(` +${n.length} more course${1===n.length?"":"s"} on this computer not linked yet โ€” open one and type `)+chalk.bold.green("link")+chalk.gray(" to join them."))}}}else console.log(chalk.yellow(" No story yet โ€” open a course with your token first."));console.log(),r--;continue}const d=c.match(/^\/?(focus|timer)(?:\s+(.*))?$/);if(d){const{FOCUS_MAX:o,FOCUS_MIN:e,FOCUS_STEP:t,getStudyTimer:n,parseFocusMinutes:l}=await import("./lib/learn-study-timer.js"),a=n(),s=(d[2]??"").trim();if(console.log(),a.showPending());else if("off"===s||"stop"===s||"end"===s||"cancel"===s)a.stop()?(await new Promise(o=>setTimeout(o,300)),a.showPending()):console.log(chalk.gray(" No focus session running. Start one: ")+chalk.bold.green("focus 30"));else if(a.active)console.log(chalk.yellow(" โฑ ")+chalk.white(`focus running ยท ${a.remainingMin()} min left`)+chalk.gray(" ยท paste a token and keep going, or ")+chalk.bold.green("focus off"));else if(""===s||"?"===s||"help"===s)console.log(chalk.bold.white(" โฑ Focus session")),console.log(chalk.gray(` How long? (${e}โ€“${o}, steps of ${t}) e.g. `)+chalk.bold.green("focus 30")),console.log(chalk.gray(" Start it here, then open any course โ€” every course you visit counts."));else{const n=l(s);if(n){if("ok"!==n.note){const l="min"===n.note?`min is ${e}`:"max"===n.note?`max is ${o}`:`rounded to the nearest ${t}`;console.log(chalk.gray(` you typed ${s} โ†’ ${l}, using ${n.min}`))}a.start(n.min),console.log(chalk.yellow(" โฑ ")+chalk.bold.white(`Focus ${n.min} min โ€” go`)+chalk.gray(" ยท now paste your token (any course counts) ยท soft reminder every 10 min ยท end early: ")+chalk.bold.green("focus off"))}else console.log(chalk.yellow(` Didn't understand "${s}". `)+chalk.gray("Type minutes, e.g. ")+chalk.bold.green("focus 30"))}console.log(),r--;continue}let u=n(i);if("back"===u.kind)break;if("continue"===u.kind){if(0===t.length){if(console.log(),console.log(chalk.yellow(" Nothing to continue โ€” no previous session on this computer.")),console.log(chalk.gray(" Paste your cohort token to start.")),console.log(),r===a){await l();break}continue}const{which:o}=u;let e=t[0];if("all"===o){console.log(),s(!0),console.log(),r-=1;continue}if("number"==typeof o){if(o<1||o>t.length){if(console.log(),console.log(chalk.yellow(` You have ${t.length} course${t.length>1?"s":""} in progress โ€” pick 1${t.length>1?`-${t.length}`:""}, or type part of its name.`)),console.log(),r===a){await l();break}continue}e=t[o-1]}else if("string"==typeof o){const n=t.filter(e=>e.curriculumId.toLowerCase().includes(o)||e.token.toLowerCase().includes(o));if(1!==n.length){if(console.log(),console.log(chalk.yellow(0===n.length?` No course in progress matches "${o}".`:` "${o}" matches ${n.length} of your courses โ€” be more specific, or use its number.`)),console.log(),s(!0),console.log(),r===a){await l();break}continue}e=n[0]}u={kind:"token",token:e.token}}if("ambiguous"===u.kind||"unknown"===u.kind){if(console.log(),console.log(chalk.yellow(` ${u.hint}`)),console.log(),r===a){console.log(chalk.gray(` That was attempt ${a} of ${a} โ€” going back to the menu.`)),console.log(chalk.gray(" Your token comes from your country team leader.")),console.log(),await l();break}continue}if(u.from){const{loadCurriculumById:o}=await import("./lib/learn-curricula.js");if(!await o(u.token,u.token)){if(console.log(),console.log(chalk.yellow(` "${u.from}" is not a token.`)),console.log(chalk.gray(" Paste the token your team leader gave you (2 letters + 8 characters).")),console.log(),r===a){await l();break}continue}}if(!/^[A-Z0-9]+DEMO01$/i.test(u.token)&&/^[A-Z]{2}[A-Z0-9]{8}$/i.test(u.token)){console.log(),console.log(chalk.gray(" Checking tokenโ€ฆ"));const{validateEAToken:o}=await import("./lib/learn-curricula.js"),e=await o(u.token);if(!e.ok){if(console.log(),console.log(chalk.red(` โœ— Token check failed: ${e.message||"validation failed"}`)+(e.code?chalk.gray(` [${e.code}]`):"")),"device_bound"===e.code?(console.log(chalk.gray(" This learn token is bound to the first computer it was used on,")),console.log(chalk.gray(" and this is a different computer. Ask the coordinator who issued")),console.log(chalk.gray(" it to move it to this device, then try again."))):"expired"===e.code?console.log(chalk.gray(" This learn token has expired โ€” ask your coordinator for a new one.")):(console.log(chalk.gray(" Possible causes:")),console.log(chalk.gray(" ยท Typo in token (check 0/O, 1/I/L, V/U)")),console.log(chalk.gray(" ยท Token expired or revoked")),console.log(chalk.gray(" ยท Network down (check connection)"))),console.log(),r<a){console.log(chalk.gray(" Try again โ€” or press Enter to go back.")),console.log();continue}await l();break}}console.log(),console.log(chalk.gray(" Opening ")+chalk.bold.cyan("learn")+chalk.gray(`: ${u.token}`)),console.log(),m({mode:"selection"}),process.env.ICOA_LEARN_EMBEDDED="1";const{setLearnSessionStarted:p}=await import("./lib/learn-outcome.js");p(!1);try{await e.parseAsync(["node","icoa","learn",u.token])}catch(o){console.log(),console.log(chalk.red(` โœ— learn failed to start: ${o instanceof Error?o.message:String(o)}`)),console.log()}finally{delete process.env.ICOA_LEARN_EMBEDDED}await l();break}}catch(o){n("learn-token-prompt-cancel",o instanceof Error?`${o.name}: ${o.message}`:String(o))}return m({mode:"selection"}),void $()}"organizer"===ne?(console.log(chalk.yellow.bold(" [National/Regional Partner]")),console.log(),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘")),console.log(chalk.bold.white(" โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•")),console.log(),console.log(chalk.yellow(" International Cyber Olympiad in AI 2026")),console.log(chalk.bold.magenta(" The World's First AI-Native CLI Operating System")),console.log(chalk.bold.magenta(" for Cybersecurity & AI Security Competition")),console.log(chalk.bold.magenta(" and Olympiad for K-12")),console.log(chalk.gray(" Sydney, Australia ยท Jun 27 - Jul 2, 2026")),console.log(),console.log(chalk.white(" Vision")),console.log(chalk.gray(" Building a global pipeline for youth cyber & AI")),console.log(chalk.gray(" security talent through education and competition.")),console.log(),console.log(chalk.white(" Capacity")),console.log(chalk.gray(" 15,000+ concurrent online examinations")),console.log(chalk.gray(" National selection, training, and education support")),console.log(),console.log(chalk.white(" Olympic Spirit")),console.log(chalk.gray(" Excellence ยท Friendship ยท Respect")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" New country accreditation & support:")),console.log(chalk.cyan(" australia@icoa2026.au")),console.log(chalk.cyan(" accreditation@icoa2026.au")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(),i?(console.log(chalk.green(` Logged in as ${r.userName}`)),console.log(chalk.white(" exam list")+chalk.gray(" Manage exams")),console.log(chalk.white(" logout")+chalk.gray(" Disconnect"))):console.log(chalk.white(" join <url>")+chalk.gray(" Connect to manage exams")),console.log(),A(),console.log()):(console.log(` ${chalk.cyan.bold("๐Ÿ† ICOA 2026 ยท International Olympiad")}`),console.log(),E&&!w()?(console.log(chalk.red(" Token was activated on a different device.")),console.log(chalk.gray(" Contact organizer for assistance.")),console.log()):i?(console.log(chalk.green.bold(` Welcome back, ${r.userName}!`)),console.log(chalk.gray(` Connected to ${r.ctfdUrl}`)),console.log(chalk.gray(" Not you? Type ")+chalk.cyan("logout")+chalk.gray(" to switch accounts")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" Ready to compete? Start here:")),console.log(),console.log(chalk.bold.cyan(" challenges")+chalk.gray(" Browse challenges by category")),console.log(chalk.white(" status")+chalk.gray(" Your score & timer")),console.log(chalk.white(" scoreboard")+chalk.gray(" Live rankings")),console.log(chalk.white(" memo")+chalk.gray(" Report an issue to organizers (one-way)")),console.log(),console.log(chalk.gray(" Tool environment:")),console.log(chalk.white(" env")+chalk.gray(" See which of the 110 CTF tools are installed")),console.log(chalk.white(" env setup")+chalk.gray(" Install anything missing (~5 min, one-time)")),console.log(chalk.bold.yellow(" โ˜… ")+chalk.bold.cyan("man <tool>")+chalk.gray(" How to USE a tool (steghide, nmapโ€ฆ) ยท ")+chalk.cyan("man tools")+chalk.gray(" = list")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.gray(" Tip: ")+chalk.cyan("help")+chalk.gray(" ยท ")+I()+chalk.gray(" ยท ")+chalk.cyan("Ctrl+C")+chalk.gray(" pauses ยท ")+chalk.cyan("quit")+chalk.gray(" closes")),console.log()):E?(Po(Zo)||_o(Zo,{recursive:!0}),console.log(chalk.green.bold(" Welcome, competitor!")),console.log(chalk.gray(` Workspace: ${Zo}`)),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" Get started:")),console.log(),console.log(chalk.white(" Step 1 ")+chalk.bold.cyan("join <url>")+chalk.gray(" Connect to competition server")),console.log(chalk.white(" Step 2 ")+chalk.bold.cyan("challenges")+chalk.gray(" Browse & solve challenges")),console.log(chalk.white(" Step 3 ")+chalk.bold.cyan("ai4ctf")+chalk.gray(" Ask AI when stuck")),console.log(),console.log(chalk.gray(" Before Step 1 โ€” make sure your tools are ready:")),console.log(chalk.white(" env")+chalk.gray(" See which of the 110 CTF tools are installed")),console.log(chalk.white(" env setup")+chalk.gray(" Install anything missing (~5 min, one-time)")),console.log(chalk.bold.yellow(" โ˜… ")+chalk.bold.cyan("man <tool>")+chalk.gray(" How to USE a tool (steghide, nmapโ€ฆ) ยท ")+chalk.cyan("man tools")+chalk.gray(" = list")),console.log(),console.log(chalk.gray(" Also: ")+chalk.white("help")+chalk.gray(" all commands")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.gray(" Tip: ")+chalk.cyan("Ctrl+C")+chalk.gray(" pauses ยท ")+I()+chalk.gray(" ยท ")+chalk.cyan("quit")+chalk.gray(" closes CLI")),console.log()):(console.log(chalk.bold.yellow(" ๐Ÿ† You reached the finals tier.")),console.log(chalk.gray(" Full sandbox ยท 110 CTF tools ยท Sydney 2026 ยท this is where finalists compete.")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" To begin, activate your competition token:")),console.log(),console.log(chalk.bold.cyan(" activate <token>")),console.log(),console.log(chalk.gray(" While waiting, explore:")),console.log(chalk.white(" ref linux")+chalk.gray(" Quick reference for Linux")),console.log(chalk.white(" ref web")+chalk.gray(" Quick reference for Web")),console.log(chalk.white(" env")+chalk.gray(" See which of the 110 CTF tools are installed")),console.log(chalk.white(" env setup")+chalk.gray(" Install anything missing (~5 min, one-time)")),console.log(chalk.white(" help")+chalk.gray(" All available commands")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.gray(" Tip: ")+chalk.cyan("Ctrl+C")+chalk.gray(" pauses ยท ")+I()+chalk.gray(" ยท ")+chalk.cyan("quit")+chalk.gray(" closes CLI")),console.log()))}const le=o=>{o.exitOverride(),o.configureOutput({writeErr:o=>{const e=o.replace(/^error:\s*/i,"").trim();e&&console.log(chalk.yellow(` ${e}`))},writeOut:o=>{console.log(o)}});for(const e of o.commands)le(e)};le(e);const ae=o({input:process.stdin,output:process.stdout,prompt:Bo(),terminal:!0,completer:Jo});S(ae),ko(!1!==y().bracketedPaste);let se=!1;if(C(!0),wo(),s&&(console.log(),console.log(chalk.yellow(" โฑ A new competition day has started (Sydney time).")),console.log(chalk.gray(" For fairness, yesterdayโ€™s sign-in has been cleared. Type ")+chalk.cyan("join <url>")+chalk.gray(" to sign in with your account.")),console.log()),So()){const o=y().userName||"this account";console.log(),console.log(chalk.yellow(" โš  This machine is signed in as ")+chalk.bold.white(o)+chalk.yellow(".")),console.log(chalk.gray(" Press ")+chalk.cyan("Enter")+chalk.gray(` to continue as ${o}, or type `)+chalk.cyan("logout")+chalk.gray(" to switch accounts.")),"logout"===(await new Promise(o=>{ae.question(chalk.white(" > "),e=>o(e.trim()))})).toLowerCase()&&(m({ctfdUrl:"",token:"",sessionCookie:"",userId:null,userName:"",teamId:null,country:""}),console.log(),console.log(chalk.green(" โœ“ Logged out. ")+chalk.gray("Run ")+chalk.cyan("join <url>")+chalk.gray(" to sign in with your own account."))),console.log()}To()&&$o(()=>ae.prompt());let re=null;const ie=ae.prompt.bind(ae);ae.prompt=o=>{if(!(j()||L()||P()||M()||U()||No()||F()||(ae.setPrompt(Bo()),o)))try{for(const o of oo()){const e="done"===o.status,t=o.cmd.length>40?`${o.cmd.slice(0,37)}โ€ฆ`:o.cmd,n=o.render?"":chalk.gray(" (")+chalk.white(t)+chalk.gray(") โ€” ")+chalk.cyan(`tasks ${o.id}`);if(console.log((e?chalk.green(" โœ“"):chalk.red(" โœ—"))+chalk.white(` background task #${o.id} ${o.status}`)+n),o.render)try{o.render()}catch{}}const o=H();o&&o!==re?(console.log(o),re=o):o||(re=null)}catch{}ie(o)};const ce=z();ce&&(console.log(chalk.cyan(" โ†ป Continue where you left off: ")+chalk.white(ce.label)+(ce.urgent?chalk.yellow(" (exam timer running)"):"")),console.log(chalk.gray(" type ")+chalk.cyan("resume")+chalk.gray(" to jump back in.")),console.log()),ae.prompt(),ae.on("line",async o=>{if(se)return;let n=vo(o.trim());if(!n)return ae.setPrompt(j()?chalk.magenta("icoa ai4ctf> "):Bo()),void ae.prompt();if(/^icoa\s+\S/i.test(n)&&(n=n.replace(/^icoa\s+/i,"")),n.startsWith("/")&&!n.startsWith("//")){const o=n.slice(1).split(/\s+/)[0].toLowerCase(),t=n.slice(1+o.length).trim();if("ai"===o)return se=!0,await async function(o,e){if(j())return void(o?await O(o):console.log(chalk.gray(" You are already in the AI chat โ€” just type your message.")));if(L())return void(o?await D(o):console.log(chalk.gray(" You are already in the CTF4AI target chat โ€” just type your message.")));if(P())return void(o?await _(o):console.log(chalk.gray(" You are already in the Embodied-AI chat โ€” just type your message.")));fo(o?`/ai ${o}`:"/ai");const t=process.exit;process.exit=()=>{throw new Error(Xo)};try{await e.parseAsync(["node","icoa","ai4ctf"])}catch(o){if(!(o instanceof Error&&o.message===Xo))throw o}finally{process.exit=t}o&&j()&&await O(o)}(t,e),se=!1,ae.setPrompt(j()?chalk.magenta("icoa ai4ctf> "):Bo()),void ae.prompt();!(j()||L()||P()||M()||U()||No())&&zo.includes(o)&&(n=n.slice(1))}if("resume"===n.toLowerCase()){const o=z();return o?(fo(`resume โ†’ ${o.command.join(" ")}`),se=!0,await Vo(e),se=!1,ae.setPrompt(j()?chalk.magenta("icoa ai4ctf> "):Bo()),void ae.prompt()):(console.log(),console.log(chalk.gray(" Nothing to resume yet โ€” start with ")+chalk.cyan("learn")+chalk.gray(" (curriculum) or ")+chalk.cyan("demo")+chalk.gray(" (taste).")),console.log(),void ae.prompt())}const a=j()||L()||P()||M()||U();if(!a&&("bg"===n.toLowerCase()||/^bg\s/i.test(n))){const o=n.replace(/^bg\s*/i,"").trim();if(!o)return console.log(),console.log(chalk.gray(" Usage: ")+chalk.cyan("bg <command>")+chalk.gray(" โ€” run a non-interactive shell command in the background.")),console.log(chalk.gray(" e.g. ")+chalk.cyan("bg nmap -p- 10.0.0.5")+chalk.gray(" ยท view: ")+chalk.cyan("tasks")),console.log(),void ae.prompt();const e=ho(),t=uo(o);po({cwd:e,input:`bg ${o}`,riskFlags:t}),t.length>0&&Y()&&console.log(chalk.yellow(` โš  Action flagged: ${t.join(", ")} โ€” logged.`));const l=J(o,e);return console.log(),console.log(chalk.cyan(` โ–ธ background task #${l.id} started`)+chalk.gray(` (${to()} running)`)),console.log(chalk.gray(" ")+chalk.white(o)),console.log(chalk.gray(" view: ")+chalk.cyan("tasks")+chalk.gray(" ยท output: ")+chalk.cyan(`tasks ${l.id}`)),console.log(),void ae.prompt()}if(!a&&("tasks"===n.toLowerCase()||/^tasks\s/i.test(n))){const o=n.replace(/^tasks\s*/i,"").trim(),e=G();if(console.log(),o){const e=K(Number(o));if(!e||Number.isNaN(Number(o)))console.log(chalk.yellow(` No background task #${o}.`)+chalk.gray(" Type ")+chalk.cyan("tasks")+chalk.gray(" to list them."));else{const o="running"===e.status?chalk.yellow:"done"===e.status?chalk.green:chalk.red;console.log(o(` #${e.id} [${e.status}]`)+chalk.white(` ${e.cmd}`)+(null!==e.exitCode?chalk.gray(` (exit ${e.exitCode})`):"")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€"));const t=e.output.trim();if(t)for(const o of t.split("\n"))console.log(chalk.gray(" ")+chalk.white(o));else console.log(chalk.gray(" (no output yet)"))}}else if(0===e.length)console.log(chalk.gray(" No background tasks. Start one with ")+chalk.cyan("bg <command>")+chalk.gray("."));else{console.log(chalk.bold.white(" Background tasks"));for(const o of e){const e="running"===o.status?chalk.yellow("โ—"):"done"===o.status?chalk.green("โœ“"):chalk.red("โœ—"),t=Math.round(((o.endedAt??Date.now())-o.startedAt)/1e3),n=(o.endedAt?`${t}s`:`${t}sโ€ฆ`).padStart(5),l=o.cmd.length>48?`${o.cmd.slice(0,45)}โ€ฆ`:o.cmd;console.log(` ${e} `+chalk.white(`#${o.id}`)+chalk.gray(` ${n} `)+chalk.white(l))}console.log(chalk.gray(" output: ")+chalk.cyan("tasks <id>"))}return console.log(),void ae.prompt()}if(!a&&/&\s*$/.test(n)&&/^challenge\s+start\s+/i.test(n)){const o=n.replace(/\s*&\s*$/,"").trim().replace(/^challenge\s+start\s+/i,"").trim().split(/\s+/),e=o.some(o=>"-n"===o||"--new"===o),t=o.find(o=>"-n"!==o&&"--new"!==o);if(!t)return console.log(),console.log(chalk.gray(" Usage: ")+chalk.cyan("challenge start <id> &")),console.log(),void ae.prompt();if(!g())return console.log(),console.log(chalk.red(" Not connected. ")+chalk.gray("Run ")+chalk.cyan("join <url>")+chalk.gray(" first.")),console.log(),void ae.prompt();fo(`challenge start ${t}${e?" --new":""} & (background)`);const l=V(`challenge start ${t}`,()=>no(t,e),o=>lo(t,o));return console.log(),console.log(chalk.cyan(` โ–ธ background task #${l.id}: `)+chalk.white(`starting ${t}`)+chalk.gray(" โ€” you can keep working; the connection info appears here when it is ready.")),console.log(),void ae.prompt()}if(!a&&n.startsWith("#")){const o=n.slice(1).trim();if(!o)return console.log(),console.log(chalk.gray(" Usage: ")+chalk.cyan("#<candidate answer>")+chalk.gray(" โ€” stage a flag/answer WITHOUT submitting it. Review with ")+chalk.cyan("drafts")+chalk.gray(".")),console.log(),void ae.prompt();const e=Z(),t=e?.session?.examId??null,l=e?e._lastQ||1:null,a=ao(o,t,l);return fo(`draft #${a.id} (not submitted)`),console.log(),console.log(chalk.green(` โœŽ draft #${a.id} saved`)+(l?chalk.gray(` (Q${l})`):"")+chalk.yellow(" โ€” NOT submitted.")),console.log(chalk.gray(" review with ")+chalk.cyan("drafts")+chalk.gray("; when sure, submit it the normal way.")),console.log(),void ae.prompt()}if(!a&&("drafts"===n.toLowerCase()||/^drafts\s/i.test(n))){const o=n.replace(/^drafts\s*/i,"").trim().toLowerCase();if("clear"===o){const o=io();return console.log(),console.log(chalk.gray(` Cleared ${o} draft${1===o?"":"s"}.`)),console.log(),void ae.prompt()}const e=o.match(/^(?:rm|remove|del|delete)\s+(\d+)$/);if(e){const o=ro(Number(e[1]));return console.log(),console.log(o?chalk.gray(` Removed draft #${e[1]}.`):chalk.yellow(` No draft #${e[1]}.`)),console.log(),void ae.prompt()}const t=Z(),l=so(t?.session?.examId??null);if(console.log(),0===l.length)console.log(chalk.gray(" No drafts yet. Stage a candidate with ")+chalk.cyan("#ICOA{maybe_this}")+chalk.gray(" โ€” it wonโ€™t submit."));else{console.log(chalk.bold.white(" Draft answers")+chalk.gray(" (staged โ€” not submitted)"));for(const o of l){const e=o.q?chalk.cyan(`Q${o.q}`.padStart(4)):chalk.gray(" ยท ");console.log(chalk.gray(` #${o.id}`)+` ${e} `+chalk.white(o.text.length>56?`${o.text.slice(0,53)}โ€ฆ`:o.text))}console.log(chalk.gray(" remove: ")+chalk.cyan("drafts rm <id>")+chalk.gray(" ยท clear all: ")+chalk.cyan("drafts clear"))}return console.log(),void ae.prompt()}if("menu"===n||"menu confirm"===n)return Y()&&"menu confirm"!==n?(console.log(),console.log(chalk.yellow(" Real exam active. Progress is auto-saved.")),console.log(chalk.gray(" To return to main menu anyway, type ")+chalk.white("menu confirm")),console.log(),void ae.prompt()):void $(ae);if(j()){se=!0;const o=await O(n);return se=!1,"exit"===o&&ae.setPrompt(Bo()),void ae.prompt()}if(L()){se=!0;const o=await D(n);return se=!1,"exit"!==o&&"solved"!==o||ae.setPrompt(Bo()),void ae.prompt()}if(P()){se=!0;const o=await _(n);return se=!1,"exit"===o&&ae.setPrompt(Bo()),ae.setPrompt(P()?chalk.bold.cyan("icoa ctf4eai> "):Bo()),void ae.prompt()}if(fo(n),"exit"===n)return Z()?(console.log(),console.log(chalk.yellow(" โš  An exam is in progress.")),console.log(chalk.white(" To return to menu without losing progress, type: ")+chalk.bold.cyan("back")),console.log(chalk.white(" To fully close ICOA CLI, type: ")+chalk.bold.cyan("quit")),console.log(chalk.gray(" Your progress is auto-saved either way.")),console.log(),void ae.prompt()):(console.log(),console.log(chalk.gray(" ")+chalk.white("exit")+chalk.gray(" returns to the main menu. To fully close ICOA CLI, type ")+chalk.bold.cyan("quit")+chalk.gray(".")),"selection"===ne&&Go(),void ae.prompt());if("quit"===n||"q"===n||"quit confirm"===n){const o=Z();return o&&"demo-free"!==o.session.examId&&"quit confirm"!==n?(console.log(),console.log(chalk.yellow(" โš  A real exam is in progress.")),console.log(chalk.gray(" Your answers are auto-saved on the server, but the exam timer keeps ticking")),console.log(chalk.gray(" on the server side even if you close the CLI.")),console.log(),console.log(chalk.white(" To leave the CLI but keep the exam alive, type: ")+chalk.bold.cyan("back")),console.log(chalk.gray(" (recommended โ€” you can resume with ")+chalk.cyan("exam q 1")+chalk.gray(" after relaunching icoa)")),console.log(),console.log(chalk.white(" To really close ICOA CLI, type: ")+chalk.bold.cyan("quit confirm")),console.log(),void ae.prompt()):(o&&"demo-free"===o.session.examId&&(console.log(),console.log(chalk.gray(" Demo paused. Resume with: ")+chalk.white("demo")+chalk.gray(" (fresh) or ")+chalk.white("exam q 1")+chalk.gray(" (continue)."))),bo(),xo(),Ao(),eo(),b(),console.log(chalk.gray(" Session saved. Use ")+chalk.white("icoa --resume")+chalk.gray(" to continue.")),co(),void c(0))}if("back"===n){const o=Z(),e=o&&"demo-free"!==o.session.examId,t=o&&"demo-free"===o.session.examId&&(()=>{const e=new Date(o.session.startedAt||0).getTime();return Date.now()-e<18e5})();if(e)console.log(),console.log(chalk.gray(" Exam paused. Your progress is saved.")),console.log(chalk.white(" Resume: exam q 1")+chalk.gray(" ยท ")+chalk.white("exam review")+chalk.gray(" ยท ")+chalk.white("exam submit")),console.log();else if(t){const e=Object.keys(o.answers).length,t=o.session.questionCount;console.log(),console.log(chalk.gray(` Demo paused (${e}/${t} answered). Resume with: `)+chalk.white("exam q 1")),console.log(chalk.gray(" Or type ")+chalk.white("demo")+chalk.gray(" to restart.")),console.log()}else{if(o&&"demo-free"===o.session.examId){const{clearExamState:o}=await import("./lib/exam-state.js");o("demo-free")}const e=y();fetch("https://practice.icoa2026.au/api/icoa/demo-stats",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"post-report-back",lang:e.language||"en",timestamp:(new Date).toISOString()}),signal:AbortSignal.timeout(5e3)}).catch(()=>{}),"selection"===ne?Go():console.log(chalk.gray(" Already at main menu."))}return void ae.prompt()}if("help"===n||"?"===n){if(Z()){se=!0;try{await e.parseAsync(["node","icoa","exam","help"])}catch{}return se=!1,void ae.prompt()}return oe(p(),ne),void ae.prompt()}if("man"===n||"manual"===n)return oe(p(),ne),console.log(),console.log(chalk.bold.yellow(" โ˜… Stuck on a tool? ")+chalk.bold.cyan("man <tool>")+chalk.gray(" e.g. ")+chalk.cyan("man steghide")+chalk.gray(" ยท ")+chalk.cyan("man tools")+chalk.gray(" = full list")),void ae.prompt();if(/^(?:man|manual)\s+\S/i.test(n))return N(n.replace(/^(?:man|manual)\s+/i,"")),void ae.prompt();if("more help"===n.toLowerCase()&&Z()){se=!0;try{await e.parseAsync(["node","icoa","exam","more-help"])}catch{}return se=!1,void ae.prompt()}if("continue"===n.toLowerCase())return console.log(),console.log(chalk.green.bold(" โ•โ•โ• AI4CTF โ€” AI as Your Teammate โ•โ•โ•")),console.log(),console.log(chalk.white(" In AI4CTF, you solve cybersecurity challenges")),console.log(chalk.white(" with AI by your side.")),console.log(),console.log(chalk.white(" In this demo, your AI teammate gives help at 3 levels:")),console.log(chalk.yellow(" hint a")+chalk.gray(" General guidance")),console.log(chalk.yellow(" hint b")+chalk.gray(" Deep analysis")),console.log(chalk.yellow(" hint c")+chalk.gray(" Critical assist")),console.log(),console.log(chalk.white(" Try it now! Type: ")+chalk.bold.green("ai4ctf")),console.log(chalk.gray(' Chat freely with your AI teammate. Type "exit" when done.')),console.log(),console.log(chalk.gray(" After ai4ctf, try: ")+chalk.bold.red("ctf4ai")+chalk.gray(' โ€” trick the AI into saying "koala"')),console.log(),void ae.prompt();if(/^ICOA-[A-Z]{2,3}-\d{1,6}$/i.test(n.trim())){se=!0;try{await e.parseAsync(["node","icoa","exam","token",n.trim()])}catch{}return se=!1,void ae.prompt()}if(/^[A-Z]{2}[0-9A-HJKMNP-TV-Z]{8}$/i.test(n.trim())){se=!0;try{await e.parseAsync(["node","icoa","exam","token",n.trim().toUpperCase()])}catch{}return se=!1,void ae.prompt()}const s=n.match(/^exam\s+([A-Z]{2}[0-9A-HJKMNP-TV-Z]{8})$/i);if(s){se=!0;try{await e.parseAsync(["node","icoa","exam","token",s[1].toUpperCase()])}catch{}return se=!1,void ae.prompt()}const r=n.match(/^exam\s+([A-Z]{2,3})$/i);if(r){se=!0;try{await e.parseAsync(["node","icoa","exam","list",r[1]])}catch{}return se=!1,void ae.prompt()}const i=n.match(/^exam\s+(\S+)$/i);if(i&&!Ho.has(i[1].toLowerCase())){const o=i[1].toUpperCase(),{normalizeTokenBody:t}=await import("./lib/token-format.js"),n=t(o),l=/^[A-Z]{2}[0-9A-HJKMNP-TV-Z]{8}$/;if(console.log(),l.test(n)){console.log(chalk.yellow(` Corrected look-alike characters: ${o} โ†’ ${n}`)),se=!0;try{await e.parseAsync(["node","icoa","exam","token",n])}catch{}return se=!1,void ae.prompt()}return console.log(chalk.red(` โœ— Not a valid exam token: ${o}`)),console.log(),console.log(chalk.gray(" An exam token is ")+chalk.bold.white("2 letters + 8 characters")+chalk.gray(" (e.g. ")+chalk.bold.yellow("AUHXP7SWMM")+chalk.gray(`) โ€” yours is ${o.length}.`)),console.log(chalk.gray(" Check for 0/O, 1/I/L, V/U mix-ups, or ask your country team leader.")),console.log(),console.log(chalk.gray(" No token yet? Try ")+chalk.bold.green("demo")+chalk.gray(" (free practice paper) or ")+chalk.bold.green("exam nations")+chalk.gray(" to see participating countries.")),console.log(),void ae.prompt()}if("clear"===n||"cls"===n)return console.clear(),void ae.prompt();if("news"===n)return To()?Io():console.log(chalk.gray(" No competition joined. Use ")+chalk.white("join <url>")+chalk.gray(".")),void ae.prompt();if("memo"===n){if(!To())return console.log(chalk.gray(" Join a competition first: ")+chalk.white("join <url>")),void ae.prompt();se=!0;try{await Lo()}catch{}return void(se=!1)}const m=jo()||Eo(y().userName||"");if("jury"===n&&m){se=!0;try{await Do()}catch{}return void(se=!1)}if(m&&jo()&&"scoreboard"===n.split(/\s+/)[0]){se=!0;try{const o=await Oo();if(console.log(),0===o.length)console.log(chalk.gray(" Scoreboard is empty."));else{console.log(chalk.bold.white(" Scoreboard"));for(const e of o.slice(0,50))console.log(chalk.gray(` ${String(e.pos).padStart(3)}. `)+chalk.white(e.name.padEnd(28).slice(0,28))+chalk.cyan(String(e.score)))}console.log()}catch{}return se=!1,void ae.prompt()}if(m&&So()){const o=n.split(/\s+/)[0];if(["challenges","open","submit","hint"].includes(o))return console.log(),console.log(chalk.yellow(" Team-leader account โ€” the challenge bracket is not available here.")),console.log(chalk.gray(" Available: ")+chalk.white("scoreboard")+chalk.gray(" ยท ")+chalk.white("news")+chalk.gray(" ยท ")+chalk.white("jury")+chalk.gray(" ยท ")+chalk.white("time")+chalk.gray(" ยท ")+chalk.white("status")+chalk.gray(" ยท ")+chalk.white("logout")),console.log(),void ae.prompt()}if(n.startsWith("activate ")){const o=n.slice(9).trim(),e=await h(o);return"ok"===e?console.log(chalk.green(" Access granted! Token bound to this device.")):"network"===e?(console.log(),console.log(chalk.red(" Could not reach the activation server.")),console.log(chalk.gray(" Activation needs internet once โ€” check your connection to ")+chalk.cyan("practice.icoa2026.au")+chalk.gray(" and run the same command again."))):"already_bound"===e?(console.log(),console.log(chalk.red(" Token already activated on a different device.")),console.log(chalk.gray(" Each token binds to the first device that uses it. If you lost the device,")),console.log(chalk.gray(" contact your proctor to have the token re-issued for a new device."))):(console.log(),console.log(chalk.red(" Token not recognized.")),console.log(chalk.gray(" Possible reasons:")),console.log(chalk.white(" โ€ข ")+chalk.gray("Typo โ€” access tokens are case-insensitive and look like ")+chalk.cyan("ICOA-XXXX-XXXX-XXXX")+chalk.gray(" (4-char hex groups, e.g. ICOA-385E-27F2-B21B)")),console.log(chalk.white(" โ€ข ")+chalk.gray("Expired โ€” ask your proctor or organizer for a fresh token")),console.log(chalk.white(" โ€ข ")+chalk.gray("Network โ€” verify connection to ")+chalk.cyan("practice.icoa2026.au")),console.log(chalk.gray(" Still stuck? type ")+chalk.cyan("help")+chalk.gray(" or try ")+chalk.cyan("exam demo")+chalk.gray(" for a free practice round."))),console.log(),void ae.prompt()}if("activate"===n)return console.log(chalk.gray(" Usage: ")+chalk.white("activate <token>")),console.log(),void ae.prompt();const d=Z();if(d){const o=n.toUpperCase().trim(),t=o=>{const e=d.questions.find(e=>e.number===o);return!!e&&("ai4ctf"===e.type||"ctf4ai"===e.type||e.options&&!e.options.A&&!e.options.B)},l=o=>{const e=d.questions.find(e=>e.number===o);return"short_answer"===e?.type},a=o=>{const e="demo-free"!==d.session.examId,t=d.questions.find(e=>e.number===o),n=Q(t?.type,e);console.log(),console.log(chalk.yellow(` Q${o} is a practical question โ€” letters (A/B/C/D) don't apply here.`)),n?(console.log(chalk.white(" Enter the AI chat for this question: ")+chalk.bold.cyan(n)),console.log(chalk.gray(" Or submit a flag directly: ")+chalk.green(`exam answer ${o} ICOA{your_flag}`))):console.log(chalk.gray(" Submit a flag: ")+chalk.green(`exam answer ${o} ICOA{your_flag}`)),console.log()};if(/^[ABCDE]$/.test(o)){const n=d._lastQ||1;if(t(n))return a(n),void ae.prompt();if(l(n))return console.log(),console.log(chalk.yellow(` Q${n} is a short-answer question โ€” type a number, not a letter.`)),console.log(chalk.gray(" Example: ")+chalk.green("42")+chalk.gray(" (or ")+chalk.green(`exam answer ${n} 42`)+chalk.gray(")")),console.log(),void ae.prompt();se=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(n),o])}catch{}return se=!1,void ae.prompt()}if(/^-?\d+$/.test(o)){const t=d._lastQ||1;if(l(t)){se=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(t),o])}catch{}return se=!1,void ae.prompt()}}const s=o.match(/^(\d+)\s+([ABCDE]|-?\d+)$/);if(s){const o=parseInt(s[1],10);if(t(o))return a(o),void ae.prompt();se=!0;try{await e.parseAsync(["node","icoa","exam","answer",s[1],s[2]])}catch{}return se=!1,void ae.prompt()}}const u=n.split(/\s+/)[0].toLowerCase(),k=/^python3?(\.\d+)?$/.test(u),x="ls"===u||"pwd"===u||"tmux"===u,v=n.startsWith("!")||u.startsWith("!")||k||x,C=new Set(["nano","vi","vim","emacs","pico","ed","code","cat","less","more","head","tail","ls","pwd","cd","base64","xxd","hexdump","od","openssl","md5sum","sha256sum","grep","find","awk","sed","strings","file","curl","wget","nc","ping","nmap","echo","bash","sh","zsh","pip","pip3","node","npm"]),A=()=>{console.log(chalk.gray(" Shell commands need ")+chalk.bold.cyan("!")+chalk.gray(" prefix. Try: ")+chalk.bold.cyan(`!${n}`)),console.log()};if("py"===u||"pylist"===u)return console.log(chalk.yellow(` ${u} is the learn-card Python scratchpad โ€” it lives inside learn.`)),console.log(chalk.gray(" Open your course first: ")+chalk.bold.cyan("learn <TOKEN>")+chalk.gray(" (or bare ")+chalk.bold.cyan("learn")+chalk.gray(" for the demo), then type ")+chalk.bold.cyan("py"===u?"/py":"/pylist")+chalk.gray(" on any card.")),console.log(),void ae.prompt();if("embodied"===ne&&!v&&!["doctor","demo2","learn","exam","ctf4eai","ctf4vla","eai","arena","lang","ref","setup","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(u))return C.has(u)?(A(),void ae.prompt()):(console.log(chalk.gray(" Not available in Embodied AI Security mode.")),console.log(chalk.white(" Try ")+chalk.bold.cyan("demo2")+chalk.gray(" (intro) ยท ")+chalk.bold.cyan("learn")+chalk.gray(" (curriculum) ยท ")+chalk.bold.cyan("exam <PD-token>")+chalk.gray(" (Paper D)")),console.log(),void ae.prompt());if("selection"===ne&&!v&&!["doctor","exam","demo","demo2","demo4","demo5","gfssm","retry","nations","next","prev","continue","setup","lang","ref","ai4ctf","ctf4ai","mark","unmark","review","submit","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(u)){if(C.has(u))return A(),void ae.prompt();if(l().includes(u))console.log(chalk.gray(` ${u} isn't available on this screen.`));else{console.log(chalk.yellow(` Unknown command: ${u}`));const o=nearestCommand(u);o&&console.log(chalk.gray(" Did you mean: ")+chalk.bold.cyan(o)+chalk.gray("?"))}if(d){const o=d._lastQ||1;console.log(chalk.white(` Resume exam: exam q ${o}`)+chalk.gray(" ยท ")+chalk.white("A/B/C/D")+chalk.gray(" to answer"))}else console.log(chalk.gray(" Try: ")+chalk.bold.cyan("learn <TOKEN>")+chalk.gray(" ยท ")+chalk.bold.cyan("exam <CC>xxxxxxxx")+chalk.gray(" ยท ")+chalk.bold.cyan("demo")+chalk.gray(" ยท ")+chalk.bold.cyan("help")+chalk.gray(" ยท ")+chalk.bold.cyan("menu"));return console.log(),void ae.prompt()}if("organizer"===ne&&!["doctor","join","exam","demo","retry","next","prev","logout","setup","lang","ref","ctf","mark","unmark","review","submit","tmux"].includes(u))return console.log(chalk.gray(" Not available in Organizer mode. Switch via: setup")),console.log(),void ae.prompt();if(!("olympiad"!==ne||p()&&w()||f(u)))return console.log(chalk.yellow(" Restricted mode. ")+chalk.gray("Enter your access token:")),console.log(chalk.white(" activate <token>")),console.log(),console.log(chalk.gray(" Free commands: ")+chalk.white("ref [topic]")+chalk.gray(", ")+chalk.white("help")+chalk.gray(", ")+chalk.white("exit")),console.log(),void ae.prompt();if(!l().includes(u)){if("tmux"===u)try{t("command -v tmux",{stdio:"ignore"})}catch{return console.log(chalk.yellow(" tmux is not installed yet.")),console.log(chalk.gray(" Install it with ")+chalk.bold.cyan("env setup")+chalk.gray(" (full toolkit) or ")+chalk.bold.cyan("darwin"===process.platform?"brew install tmux":"sudo apt install tmux")+chalk.gray(".")),console.log(),void ae.prompt()}if(Yo.has(u))return console.log(chalk.yellow(` "${u}" is a shell command โ€” the ICOA prompt isn't a shell.`)),console.log(chalk.gray(" In real-exam mode, prefix with ! to run inside the sandbox: ")+chalk.cyan(`!${n}`)),console.log(),void ae.prompt();if(/(?:^|\s)(?:\/(?!home\/|Users\/|tmp\/)|\.\.\/|~\/)/.test(n)&&!n.startsWith("cd ")){const o=/(?:^|\s)\/(?!home\/\w+\/icoa-workspace|Users\/\w+\/icoa-workspace|tmp\/)/.test(n),e=/\.\./.test(n);if(o||e)return console.log(chalk.red(" Blocked: access outside workspace is not allowed.")),console.log(chalk.gray(` Workspace: ${Zo}`)),console.log(),void ae.prompt()}let o=n.startsWith("!")?n.slice(1).trim():n;if("darwin"===process.platform){const e="/opt/homebrew/opt/python@3.12/bin/python3.12";o=o.replace(/^python3?\s/,`${e} `).replace(/^(python3|python)$/,e)}else if("win32"===process.platform){const e=(()=>{try{return t("py -3 --version",{stdio:["ignore","ignore","ignore"],timeout:1500}),"py -3"}catch{}return"python"})();o=o.replace(/^python3?(\.\d+)?\s/,`${e} `).replace(/^python3?(\.\d+)?$/,e)}else{const e=(()=>{try{return t("which python3.12",{stdio:"ignore"}),"python3.12"}catch{return"python3"}})();o=o.replace(/^python\s/,`${e} `).replace(/^python$/,e)}const e=ho(),l=uo(n);po({cwd:e,input:n,riskFlags:l}),l.length>0&&Y()&&(console.log(chalk.yellow(` โš  Action flagged: ${l.join(", ")} โ€” logged.`)),console.log()),/^(\S*python3?(\.\d+)?)\s*$/.test(o)&&(o=`PYTHONSTARTUP="${function(){const o=Uo(Ro(),".icoa");Po(o)||_o(o,{recursive:!0});const e=Uo(o,"python-startup.py");let t="";if(Po(e))try{t=Mo(e,"utf-8")}catch{}return t!==qo&&Fo(e,qo),e}()}" ${o}`,console.log(),console.log(chalk.cyan(" โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”")),console.log(chalk.bold.white(" Python ready โ€” ICOA exam toolkit pre-loaded")),console.log(chalk.cyan(" โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”")),console.log(),console.log(chalk.white(" Already imported: ")+chalk.gray("base64, struct, hashlib, re, json, binascii")),console.log(chalk.white(" Also available: ")+chalk.gray("requests, bs4, numpy, PIL.Image, AES, pad/unpad, xor, p32/u32/p64/u64")),console.log(),console.log(chalk.yellow(" Quick examples:")),console.log(chalk.gray(' base64.b64decode("aGVsbG8=") ')+chalk.gray("# decode base64")),console.log(chalk.gray(' bytes.fromhex("48656c6c6f") ')+chalk.gray("# hex โ†’ bytes")),console.log(chalk.gray(' "ICOA{x}".encode() ')+chalk.gray("# str โ†’ bytes")),console.log(chalk.gray(" [chr(c) for c in [73,67,79,65]] ")+chalk.gray("# ASCII codes")),console.log(chalk.gray(' xor(bytes.fromhex("0a2b"), b"IC") ')+chalk.gray("# pwntools XOR")),console.log(),console.log(chalk.gray(" Exit: ")+chalk.white("exit()")+chalk.gray(" or Ctrl-D")),console.log(chalk.cyan(" โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”")),console.log()),se=!0;try{await mo()&&await go()?await yo(o,ae):await Ko(o,ae,e)}catch{console.log(chalk.yellow(` Command failed: ${u}`))}return se=!1,console.log(),void ae.prompt()}se=!0;const I=n.trim(),T=I.toLowerCase();let S,E=null,F="";if(d)if("submit"===T)E="final";else if(T.startsWith("submit ")){let o=I.slice(7).trim();/^submit\s+/i.test(o)&&(o=o.replace(/^submit\s+/i,"").trim()),o=o.replace(/^["'`]+|["'`]+$/g,"").trim(),o&&/^ICOA\{[^}]*\}?$/i.test(o)?(E="flag",F=o):o&&/^[ABCDE]$/i.test(o)&&(E="flag",F=o.toUpperCase())}else/^ICOA\{[^}]+\}$/i.test(I)&&(E="flag",F=I);S="final"===E?["exam","submit"]:"flag"===E?["exam","answer",String(d?._lastQ||1),F]:mapCommand(n);const R="ctf"===S[0]&&"join"===S[1];R&&ae.pause(),process.exit=()=>{throw new Error(Xo)};try{await e.parseAsync(["node","icoa",...S])}catch(o){const e=o instanceof Error?o.message:String(o);if(e===Xo);else if(e.includes("commander.unknownCommand")){const o=nearestCommand(u.split(/\s+/)[0]||u);console.log(chalk.yellow(` Unknown command: ${u}.`)),o&&console.log(chalk.gray(" Did you mean: ")+chalk.bold.cyan(o)+chalk.gray("?")),console.log(chalk.gray(" Type ")+chalk.cyan("help")+chalk.gray(" for the full command list."))}else e.includes("commander.missingArgument")||"commander.missingArgument"===o?.code?"submit"===u||"flag"===u?(console.log(chalk.yellow(" Incomplete โ€” usage: ")+chalk.cyan("submit <challenge#> <flag>")),console.log(chalk.gray(" Put the number AND the flag on one line, e.g. ")+chalk.cyan("submit 44 pecan{...}"))):(console.log(chalk.yellow(` Incomplete command: ${u}`)),console.log(chalk.gray(" Type ")+chalk.cyan("help")+chalk.gray(" for usage."))):e.includes("commander.")||(e.includes("fetch failed")||e.includes("ECONNREFUSED")||e.includes("ETIMEDOUT"))&&console.log(chalk.yellow(" Network error. Check your connection."))}finally{process.exit=c,se=!1,R&&ae.resume()}j()?ae.setPrompt(chalk.magenta("icoa ai4ctf> ")):L()?ae.setPrompt(chalk.red("icoa ctf4ai> ")):P()&&ae.setPrompt(chalk.bold.cyan("icoa ctf4eai> ")),console.log(),ae.prompt()}),ae.on("SIGINT",()=>{if(console.log(),j()||L())console.log(chalk.yellow(" Ctrl+C did not close ICOA CLI โ€” you are still in the AI chat.")),console.log(chalk.white(" Type ")+chalk.bold.cyan("exit")+chalk.white(" to leave the chat and return to the menu."));else if(Z()){const o="demo-free"!==Z().session.examId;console.log(chalk.yellow(" Ctrl+C did NOT close ICOA CLI.")),console.log(chalk.gray(` Your ${o?"exam":"demo"} is paused and every answer is auto-saved.`)),console.log(),console.log(chalk.white(" Resume: ")+chalk.cyan("exam q 1")+chalk.gray(" ยท Back to menu: ")+chalk.cyan("back")+chalk.gray(" ยท Close CLI: ")+chalk.cyan(o?"quit confirm":"quit"))}else console.log(chalk.yellow(" Ctrl+C did not close ICOA CLI โ€” you are still at the ")+chalk.cyan("icoa>")+chalk.yellow(" prompt.")),console.log(chalk.gray(" Keep typing โ€” ")+chalk.cyan("help")+chalk.gray(" lists commands. (Only ")+chalk.cyan("quit")+chalk.gray(" or Ctrl+D actually close the CLI.)"));console.log(),ae.prompt()}),ae.on("close",()=>{n("main-rl-close",`stdin.isTTY=${!0===process.stdin.isTTY}`),console.log(),console.log(chalk.gray(" input closed โ€” leaving icoa. Run icoa --resume to continue.")),bo(),xo(),Ao(),eo(),b(),co(),c(0)}),"1"===process.env.ICOA_AUTO_RESUME&&(delete process.env.ICOA_AUTO_RESUME,z()&&(se=!0,await Vo(e),se=!1,ae.setPrompt(j()?chalk.magenta("icoa ai4ctf> "):Bo()),ae.prompt()))}function Ko(o,t,n){return new Promise(l=>{const a=process.stdin,s=!!a.isTTY&&!!a.isRaw;if(t.pause(),a.isTTY&&"function"==typeof a.setRawMode)try{a.setRawMode(!1)}catch{}const r=e(o,{shell:!0,stdio:"inherit",cwd:n||process.cwd()}),i=()=>{if(a.isTTY&&"function"==typeof a.setRawMode&&s)try{a.setRawMode(!0)}catch{}Co(),t.resume(),l()};r.on("close",e=>{if(127===e){const e=nearestCommand(o.trim().split(/\s+/)[0]??"");e&&console.log(chalk.gray(" Did you mean: ")+chalk.bold.cyan(e)+chalk.gray("?"))}i()}),r.on("error",i)})}export function mapCommand(o){const e=o.split(/\s+/),t=e[0].toLowerCase(),n=e.slice(1);if("aienv"===t&&["run","python","py"].includes((n[0]??"").toLowerCase()))return E(o);if(("submit"===t||"flag"===t)&&n.length>=2)return["ctf","submit",n[0],n.slice(1).join(" ").trim().replace(/^["'`]+|["'`]+$/g,"")];if("connect"===t&&n.length>=2){const e=E(o);return["connect",e[1]??n[0],e.slice(2).join(" ")]}return s(t,n)||[t,...n]}function oe(o,e="olympiad"){if(console.log(),"selection"===e||"organizer"===e)return console.log(chalk.bold.white(" Exam")),console.log(chalk.white(" join <url> ")+chalk.gray("Connect to exam server")),console.log(chalk.white(" exam list ")+chalk.gray("Available exams")),console.log(chalk.white(" exam start <id> ")+chalk.gray("Begin an exam")),console.log(chalk.white(" exam q [n] ")+chalk.gray("View questions")),console.log(chalk.white(" exam answer <n> <X> ")+chalk.gray("Answer question")),console.log(chalk.white(" exam review ")+chalk.gray("Review all answers")),console.log(chalk.white(" exam submit ")+chalk.gray("Submit for grading")),console.log(chalk.white(" exam result ")+chalk.gray("View your score")),console.log(),console.log(chalk.bold.white(" System")),console.log(chalk.white(" ref [topic] ")+chalk.gray("Quick reference")),console.log(chalk.white(" setup ")+chalk.gray("Settings / switch mode")),console.log(chalk.white(" lang [code] ")+chalk.gray("Switch language")),console.log(chalk.white(" clear ")+chalk.gray("Clear screen")),console.log(chalk.white(" exit ")+chalk.gray("Quit")),void console.log();if(!o)return console.log(chalk.bold.yellow(" Restricted Mode โ€” activate with a token to unlock all commands")),console.log(),console.log(chalk.white(" activate <token> ")+chalk.gray("Unlock full access")),console.log(chalk.white(" ref [topic] ")+chalk.gray("Quick reference")),console.log(chalk.white(" exit ")+chalk.gray("Quit")),void console.log();console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log(chalk.bold.white(" How it works")),console.log(),console.log(chalk.gray(" 1. Browse ")+chalk.white("challenges")+chalk.gray(" and pick one")),console.log(chalk.gray(" 2. ")+chalk.white("open <id>")+chalk.gray(" to read the challenge")),console.log(chalk.gray(" 3. Use ")+chalk.white("ai4ctf")+chalk.gray(" to chat with AI when stuck")),console.log(chalk.gray(" 4. ")+chalk.white("submit <id> <flag>")+chalk.gray(" to score points")),console.log(chalk.gray(" 5. Check ")+chalk.white("scoreboard")+chalk.gray(" to track your rank")),console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log();for(const o of["Competition","AI Teammate","Tools","System"]){console.log(chalk.bold.white(` ${o}`));for(const e of a(o))console.log(chalk.white(` ${e.label.padEnd(20)}`)+chalk.gray(e.text)),"System"===o&&"resume"===e.label&&console.log(chalk.white(" #<candidate> ")+chalk.gray("Stage a draft answer (never auto-submits)"));"Tools"===o&&console.log(chalk.white(" man <tool> ")+chalk.bold.yellow("โ˜… ")+chalk.gray("How to use a tool (steghide, nmapโ€ฆ); ")+chalk.cyan("man tools")+chalk.gray(" = list. Bare ")+chalk.cyan("man")+chalk.gray(" = this list.")),console.log()}}
1
+ import{createInterface as o}from"node:readline";import{spawn as e,execSync as t}from"node:child_process";import chalk from"chalk";import{appendExitLog as n}from"./lib/exit-log.js";import{dispatchable as l,helpRows as s,shortcutFor as a,subcommandsOf as r,surface as i}from"./lib/commands.js";import{distance as c}from"fastest-levenshtein";import{isConnected as g,getConfig as y,saveConfig as d}from"./lib/config.js";import{ensureLangCache as m}from"./lib/translations-fetcher.js";import{loadUiPack as u}from"./lib/i18n.js";import{isActivated as p,activateToken as h,isFreeCommand as f,isDeviceMatch as w,recordExit as b,recordResume as k,isFirstRunOrUpgrade as x,markVersionSeen as v}from"./lib/access.js";import{setReplMode as C}from"./lib/ui.js";import{returnToMainMenu as $,printMenuHint as A,menuHintInline as I,registerRealExit as T}from"./lib/menu-nav.js";import{setMainRl as S}from"./lib/main-rl.js";import{shellSplit as E}from"./lib/shell-split.js";import{isChatActive as O,handleChatMessage as j}from"./commands/ai4ctf.js";import{renderToolMan as N}from"./lib/tool-man.js";import{isCtf4aiActive as L,handleCtf4aiMessage as D}from"./commands/ctf4ai-demo.js";import{isCtf4VlaActive as P,handleCtf4VlaMessage as _}from"./commands/ctf4vla.js";import{isDemo2Active as M}from"./commands/demo2.js";import{isSprintActive as F}from"./commands/sprint.js";import{isCardDeckActive as U}from"./lib/card-engine.js";import{hasAnySimHistory as R,lastArmAt as q,lastBundledAt as W,lastSimAt as B}from"./lib/sim-cooldown.js";import{getExamState as Z,getRealExamState as Y,getDemoState as X,practicalChatCommand as Q}from"./lib/exam-state.js";import{resolveResumePoint as z}from"./lib/resume.js";import{buildStatusLine as H}from"./lib/statusline.js";import{startBgTask as J,startAsyncTask as V,listBgTasks as G,getBgTask as K,drainCompleted as oo,killAllBgTasks as eo,runningCount as to}from"./lib/bgtasks.js";import{computeStart as no,renderStart as lo}from"./commands/challenge.js";import{addDraft as so,listDrafts as ao,removeDraft as ro,clearDrafts as io}from"./lib/drafts.js";import{resetTerminalTheme as co}from"./lib/theme.js";import{ensureSandbox as go,runInSandbox as yo,isDockerAvailable as mo}from"./lib/sandbox.js";import{checkShellRisk as uo,logShellAudit as po,getActiveCwd as ho}from"./lib/exam-sandbox.js";import{logCommand as fo}from"./lib/logger.js";import{startLogSync as wo,stopLogSync as bo}from"./lib/log-sync.js";import{installInputDynamics as ko,uninstallInputDynamics as xo,stripTerminalMarkers as vo,rearmFocusMode as Co}from"./lib/input-dynamics.js";import{startBroadcastPoll as $o,stopBroadcastPoll as Ao,showBroadcast as Io,isCompetitionJoined as To,isMelCompetition as So,isLeaderAccount as Eo,isLeaderSession as Oo,fetchPublicScoreboard as jo,isCommsActive as No}from"./lib/comms.js";import{enterMemoScreen as Lo,enterJuryScreen as Do}from"./commands/comms.js";import{existsSync as Po,mkdirSync as _o,readFileSync as Mo,writeFileSync as Fo}from"node:fs";import{join as Uo}from"node:path";import{homedir as Ro}from"node:os";const qo="# ICOA exam interactive startup โ€” auto-loaded by PYTHONSTARTUP\nimport base64, struct, hashlib, re, json, os, sys, binascii\ntry: import requests\nexcept ImportError: pass\ntry: from Crypto.Cipher import AES\nexcept ImportError: pass\ntry: from Crypto.Util.Padding import pad, unpad\nexcept ImportError: pass\ntry: from pwn import xor, p32, u32, p64, u64\nexcept ImportError: pass\ntry: import bs4\nexcept ImportError: pass\ntry: import numpy as np\nexcept ImportError: pass\ntry: from PIL import Image\nexcept ImportError: pass\n",Wo=Date.now();function Bo(){return So()?chalk.yellow("icoa 2026> "):Y()?chalk.cyan("icoa exam> "):function(){const o=X();return!(!o||"demo-free"!==o.session?.examId)&&new Date(o.session.startedAt||0).getTime()>=Wo}()?chalk.yellow("icoa demo> "):chalk.green("icoa> ")}const Zo=Uo(Ro(),"icoa-workspace"),Yo=new Set(["sudo","su","doas","pkexec","brew","apt","apt-get","yum","choco","npm","npx","pip","pip3","shutdown","reboot","halt","mkfs","fdisk","dd","iptables","ufw"]),Xo="__REPL_NO_EXIT__",Qo="2.5.1",zo=i();export function nearestCommand(o,e=2){const t=o.trim().toLowerCase();if(!t)return null;let n={word:"",dist:Number.POSITIVE_INFINITY};for(const o of zo){const e=c(t,o);e<n.dist&&(n={word:o,dist:e})}return n.dist>0&&n.dist<=e?n.word:null}const Ho=new Set(["answer","demo","demo-retry","help","list","mark","more-help","nations","next","prev","q","reset","result","review","setup","start","submit","token","unmark","status","time"]);function Jo(o){const e=o.replace(/^\s+/,"");if(/^\/\S*$/.test(e)){const o=e.slice(1).toLowerCase();return[zo.filter(e=>e.startsWith(o)).map(o=>`/${o}`),e]}const t=e.split(/\s+/);if(t.length<=1){const o=(t[0]??"").toLowerCase();return[zo.filter(e=>e.startsWith(o)).slice(),o]}if(2===t.length){const o=r(t[0].toLowerCase());if(o){const e=t[1].toLowerCase();return[o.filter(o=>o.startsWith(e)).slice(),e]}}return[[],o]}async function Vo(o){const e=z();if(!e)return null;const t=process.exit;process.exit=()=>{throw new Error(Xo)};try{await o.parseAsync(["node","icoa",...e.command])}catch(o){if(!(o instanceof Error&&o.message===Xo))throw o}finally{process.exit=t}return e}function Go(){console.log(),console.log(` ${chalk.cyan.bold("๐ŸŽฏ ICOA 2026 ยท National Selection")}`),console.log(),console.log(" "+chalk.bold.cyan("learn ")+chalk.white("ACxxxxxxxx")+chalk.gray(" โ†’ ai4ctf-12 (AI as your CTF teammate)")),console.log(" "+chalk.bold.cyan("learn ")+chalk.white("CAxxxxxxxx")+chalk.gray(" โ†’ ctf4ai-12 (red-team software AI)")),console.log(" "+chalk.bold.cyan("learn ")+chalk.white("EAxxxxxxxx")+chalk.gray(" โ†’ ctf4eai-12 (red-team embodied AI)")),console.log(" "+chalk.bold.cyan("exam ")+chalk.white("<CC>xxxxxxxx")+chalk.gray(" โ†’ Paper A/B/C/D/E (country exam token)")),console.log(" "+chalk.bold.cyan("demo")+chalk.gray(" โ†’ free practice")),console.log(" "+chalk.bold.cyan("lang")+chalk.white(" es")+chalk.gray(" โ†’ switch language")),console.log(" "+chalk.gray("help ยท menu ยท quit")),console.log()}export async function startRepl(e,s){process.env.ICOA_INSIDE_REPL="1";let a=!1;if(So()){const o=y().joinedAt,e=o=>new Intl.DateTimeFormat("en-CA",{timeZone:"Australia/Sydney",year:"numeric",month:"2-digit",day:"2-digit"}).format(o);o&&e(new Date(o))===e(new Date)||(d({ctfdUrl:"",token:"",sessionCookie:"",userId:null,userName:"",teamId:null,country:"",joinedAt:""}),a=!0)}const r=y(),i=g(),c=process.exit.bind(process);T(c);const E=p();if(r.language&&"en"!==r.language&&(await m(r.language,{silent:!0}),u(r.language)),r.demoCleanedForVersion!==Qo){try{const{existsSync:o,unlinkSync:e}=await import("node:fs"),{join:t}=await import("node:path"),{getIcoaDir:n}=await import("./lib/config.js"),l=t(n(),"demo-state.json");o(l)&&e(l)}catch{}d({demoCleanedForVersion:Qo})}const{select:X,confirm:Co}=await import("@inquirer/prompts"),Wo=r.mode||"",ee=""===Wo?"instant":["instant","learn","selection","olympiad"].includes(Wo)?Wo:"selection",te=[{name:` ${chalk.bold("โšก Try ICOA in 30 seconds")} ${chalk.gray("โ€”")} ${chalk.gray("watch ยท no token needed")}`,value:"instant"},{name:` ${chalk.bold("๐Ÿง  Learn")} ${chalk.gray("โ€”")} ${chalk.gray("team token ยท skill up")}`,value:"learn"},{name:` ${chalk.bold("๐ŸŽฏ National Selection")} ${chalk.gray("โ€”")} ${chalk.gray("country exam token ยท aim for finals")}`,value:"selection"},{name:` ${chalk.bold("๐Ÿ† International Olympiad")} ${chalk.gray("โ€”")} ${chalk.gray("finals stage ยท Sydney 2026 ยท full sandbox")}`,value:"olympiad"},{name:` ${chalk.gray("โ„น๏ธ About ICOA")} ${chalk.gray("ยท")} ${chalk.gray("what this is ยท how to join")}`,value:"about"}];""===Wo&&(console.log(chalk.green(" ๐Ÿ‘‹ First time here? ")+chalk.white("Just press ")+chalk.bold.cyan("Enter")+chalk.white(" โ€” youโ€™ll see ICOA in 30 seconds, no signup needed.")),console.log()),console.log(chalk.gray(" Type ")+chalk.bold.cyan("menu")+chalk.gray(" from anywhere to return here.")),console.log();let ne="";for(;!ne;){let o;const e=process.env.ICOA_TEST_BOOT_MODE;if(e&&["instant","learn","selection","olympiad"].includes(e))o=e;else try{o=await X({message:"Mode",choices:te,default:ee||"instant"})}catch(o){throw o instanceof Error&&"ExitPromptError"===o.name&&(console.log(),console.log(chalk.gray(" Goodbye.")),process.exit(0)),o}if("about"!==o)ne=o;else{console.clear(),console.log(),console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log(chalk.bold.yellow(" ICOA")+chalk.white(" โ€” AI-Native CLI OS for Cyber & AI Security")),console.log(chalk.gray(" Olympiad & Competition ยท K-12 to University")),console.log(chalk.cyan(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(),console.log(chalk.bold.white(" What Makes ICOA Different")),console.log(chalk.gray(" ยท AI-native AI teammate, AI adversary, AI translation")),console.log(chalk.gray(" ยท CLI OS Complete competition environment in terminal")),console.log(chalk.gray(" ยท 110 tools pwntools, z3, gdb, nmap, sleuthkit... pre-configured")),console.log(chalk.gray(" ยท Global scale 15,000+ concurrent exams ยท 20+ languages")),console.log(),console.log(chalk.bold.white(" Three Frontiers of AI Security")),console.log(` ${chalk.green.bold("AI4CTF")}${chalk.gray(" AI as teammate โ€” 5 CTF disciplines, 5-hour endurance round")}`),console.log(` ${chalk.red.bold("CTF4AI")}${chalk.gray(" AI as target โ€” the AI system itself is the objective")}`),console.log(` ${chalk.cyan.bold("CTF4EAI")}${chalk.gray(" Embodied-AI Arena โ€” probe robot policies in live simulation")}`),console.log(),console.log(chalk.bold.white(" First Edition โ€” Sydney 2026 ")+chalk.green.bold("โœ“ held")),console.log(chalk.gray(" ยท Jun 27 - Jul 2, 2026 ยท University of Technology Sydney")),console.log(chalk.gray(" ยท 65 competitors ยท 20 countries & regions (10 on-site, 10 remote)")),console.log(chalk.gray(" ยท 36 awards โ€” 6 Gold ยท 11 Silver ยท 17 Bronze ยท 2 Honorable Mentions")),console.log(chalk.gray(" ยท Champion: Oleg Uteshev ยท Embodied-AI Arena Gold: Kingsley Lim (AU)")),console.log(chalk.gray(" ยท Founding Charter signed โ€” ICOA is now a permanent institution")),console.log(),console.log(chalk.bold.white(" Next: ICOA 2027")+chalk.gray(" โ€” 20 more countries already accredited")),console.log(),console.log(chalk.bold.white(" Organized by")+chalk.gray(" ASRA (Australia) ยท ICO Foundation Inc")),console.log(chalk.bold.white(" Contact ")+chalk.cyan(" australia@icoa2026.au ยท accreditation@icoa2026.au")),console.log(chalk.bold.white(" Website ")+chalk.cyan.underline(" https://icoa2026.au")+chalk.gray(" ยท press: ")+chalk.cyan.underline("https://icoa2026.au/press/")),console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log();try{const{input:o}=await import("@inquirer/prompts"),e=()=>o({message:chalk.gray("Press Enter to return..."),theme:{prefix:"",style:{message:o=>o}}}),t=Date.now();await e(),Date.now()-t<200&&await e()}catch{}console.clear()}}if("olympiad"===ne&&"olympiad"!==ee){console.log(),console.log(chalk.yellow(" This mode will download ~500MB of CTF tools and AI models."));let o=!0;try{o=await Co({message:"Continue?",default:!0})}catch(e){if(!(e instanceof Error&&"ExitPromptError"===e.name))throw e;o=!1}o||(ne="selection",console.log(chalk.gray(" Switched to National Selection mode.")))}if(ne!==ee&&d({mode:ne}),console.log(),"olympiad"===ne&&x(Qo)){v(Qo),console.log(chalk.gray(" Checking competition environment..."));const{execSync:o}=await import("node:child_process"),e=[{name:"pwntools",cmd:'python3 -c "import pwn"'},{name:"z3-solver",cmd:'python3 -c "import z3"'},{name:"numpy",cmd:'python3 -c "import numpy"'},{name:"requests",cmd:'python3 -c "import requests"'}];let t=0;for(const n of e)try{o(n.cmd,{stdio:"ignore"})}catch{t++}t>0?(console.log(chalk.yellow(` ${t} core competition libraries missing.`)),console.log(chalk.gray(" Run ")+chalk.white("env setup")+chalk.gray(" when you are ready to install them.")),console.log()):(console.log(chalk.green(" All core libraries ready.")),console.log())}if(s){const o=k();if(o){const e=Math.floor(o.awaySeconds/60),t=o.awaySeconds%60;console.log(chalk.yellow(` Session resumed. Away: ${e}m ${t}s | Total exits: ${o.exitCount}`)),console.log()}}if("selection"===ne)console.log(chalk.gray(" โ”€โ”€โ”€ exam hall ยท 90 min per paper once started ยท no pause โ”€โ”€โ”€")),console.log(),Go();else if("embodied"===ne)!function(){console.log(chalk.cyan.bold(" [๐Ÿค– ctf4eai โ€” Embodied AI Security]")),console.log(),console.log(chalk.bold.cyan(" CTF4EAI")+chalk.gray(" โ€” ICOA 2026's ")+chalk.bold.white("Pioneer Round")),console.log(chalk.gray(" an independent parallel track alongside the scored main events: ")+chalk.green("AI4CTF")+chalk.gray(" (Day 1) and ")+chalk.red("CTF4AI")+chalk.gray(" (Day 2)")),console.log(),console.log(chalk.white(" Embodied AI is at its ImageNet moment.")),console.log(chalk.gray(" VLA models, MuJoCo physics, real robot arms.")),console.log(chalk.gray(" Real models, real physics, real attack surfaces.")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€"));const o=W()>0||B()>0,e=q()>0,t=R();o&&e?console.log(chalk.bold.yellow(" Next up: ")+chalk.bold.cyan("โ‘ข demo2")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ฃ learn LEARNDEMO01")+chalk.gray(" (sim โœ“ ยท sim arm โœ“)")):t?console.log(chalk.bold.yellow(" Next up: ")+(e?chalk.bold.cyan("โ‘  sim")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ข demo2"):chalk.bold.cyan("โ‘ก sim arm")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ข demo2"))+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ฃ learn LEARNDEMO01")):console.log(chalk.bold.yellow(" First time? Try in order: ")+chalk.bold.cyan("โ‘  sim")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ก sim arm")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ข demo2")+chalk.gray(" โ†’ ")+chalk.bold.cyan("โ‘ฃ learn LEARNDEMO01")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.bold.green(" sim")+chalk.gray(" ")+chalk.bold.cyan("โ‘ ")+chalk.gray(" ")+chalk.bold.yellow("โ˜… INSTANT")+chalk.gray(" โ€” 9-robot group dance, no wait, no setup")),console.log(chalk.bold.green(" sim arm")+chalk.gray(" ")+chalk.bold.cyan("โ‘ก")+chalk.gray(" interactive 6-DOF arm sandbox โ€” type joint values, watch")),console.log(chalk.bold.green(" demo2")+chalk.gray(" ")+chalk.bold.cyan("โ‘ข")+chalk.gray(" ~8 min interactive intro + live MuJoCo sim")),console.log(chalk.bold.green(" learn LEARNDEMO01")+chalk.gray(" ")+chalk.bold.cyan("โ‘ฃ")+chalk.gray(" free 11-card intro (paste this command as-is)")),console.log(chalk.bold.green(" learn ")+chalk.bold.yellow("EA")+chalk.gray(" + 8 chars full 96 / 360 curriculum (team-issued)")),console.log(chalk.bold.green(" exam ")+chalk.bold.yellow("PDxxxxxxxx")+chalk.gray(" Paper D (CTF4EAI) โ€” national selection contestants")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(),console.log(chalk.gray(" Three open tiers: ")+chalk.green("free 11")+chalk.gray(" ยท ")+chalk.yellow("registered 100")+chalk.gray(" ยท ")+chalk.bold.magenta("national team 480")+chalk.gray(" (PhD-ready)")),console.log(chalk.gray(" Country team contact: ")+chalk.cyan("australia@icoa2026.au")),console.log(),A(),console.log()}();else if("instant"===ne)console.log(chalk.cyan.bold(" [โšก Try ICOA in 30 seconds โ€” no token needed]")),console.log(),console.log(chalk.gray(" Three free tastes โ€” just type the word and press Enter:")),console.log(),console.log(chalk.bold.green(" demo ")+chalk.gray(" Paper A/B/C taste โ€” 10 MCQs, no timer ")+chalk.bold.cyan("๐ŸŽฏ selection-style")),console.log(chalk.bold.green(" demo2 ")+chalk.gray(" Embodied-AI mini-demo โ€” robots & MuJoCo ")+chalk.bold.yellow("๐Ÿค– hands-on")),console.log(chalk.bold.green(" kaggle")+chalk.gray(" ML practice โ€” train a model, real board ")+chalk.bold.magenta("๐Ÿ“Š data-science")),console.log(),console.log(chalk.gray(" Type ")+chalk.bold.cyan("demo")+chalk.gray(", ")+chalk.bold.cyan("demo2")+chalk.gray(" or ")+chalk.bold.cyan("kaggle")+chalk.gray(" to start ยท ")+chalk.bold.cyan("menu")+chalk.gray(" to go back ยท ")+chalk.bold.cyan("quit")+chalk.gray(" to exit")),console.log(),d({mode:"selection"}),ne="selection";else{if("learn"===ne){console.log(chalk.cyan.bold(" [๐Ÿง  Learn]")),console.log();const o=await(async()=>{try{const o=await import("./lib/learn-state.js");return{sessions:o.listLearnSessions(),listMax:o.CONTINUE_LIST_MAX}}catch{return{sessions:[],listMax:5}}})(),t=o.sessions,l=o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o)?`${o.slice(0,2)}โ€ขโ€ขโ€ขโ€ขโ€ขโ€ข${o.slice(-2)}`:o,s=o=>{const e=new Date(o);if(Number.isNaN(e.getTime()))return"";const t=o=>new Date(o.getFullYear(),o.getMonth(),o.getDate()).getTime(),n=Math.round((t(new Date)-t(e))/864e5);return n<0?"":0===n?"today":1===n?"yesterday":n<30?`${n} days ago`:"a while back"},a=e=>{const n=e?t:t.slice(0,o.listMax),a=o=>Math.max(...n.map(e=>o(e).length)),r=a(o=>o.curriculumId),i=a(o=>`card ${o.currentCard}/${o.totalCards}`),c=a(o=>s(o.lastSeenAt));return n.forEach((o,e)=>{const t=o.token===o.curriculumId?"":` ${l(o.token)}`;console.log(chalk.green(` ${e+1} `)+chalk.bold.white(o.curriculumId.padEnd(r))+chalk.gray(` ${`card ${o.currentCard}/${o.totalCards}`.padEnd(i)} ${s(o.lastSeenAt).padEnd(c)}${t}`))}),n.length};if(1===t.length){const o=t[0],e=s(o.lastSeenAt);console.log(chalk.green(" โ–ธ Continue ")+chalk.bold.white(o.curriculumId)+chalk.gray(` ยท card ${o.currentCard}/${o.totalCards}${e?` ยท ${e}`:""} ยท ${l(o.token)}`)),console.log(chalk.gray(" type ")+chalk.bold.green("c")+chalk.gray(" or ")+chalk.bold.green("continue")+chalk.gray(" to resume ยท Enter to go back")),console.log()}else if(t.length>1){console.log(chalk.green(" โ–ธ Continue"));const o=a(!1);t.length>o&&console.log(chalk.gray(` +${t.length-o} more โ€” type `)+chalk.bold.green("c all")+chalk.gray(" to list them")),console.log(chalk.gray(" type ")+chalk.bold.green("c")+chalk.gray(" to resume 1 ยท ")+chalk.bold.green("c 2")+chalk.gray(" to switch ยท Enter to go back")),console.log()}{const{doorStoryLines:o,doorWelcomeLines:e,fetchProfilesForLocalTokens:n}=await import("./lib/learn-door.js"),{learnW:l}=await import("./lib/learn-render.js");let s=null;if(t.find(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token))){const a=await n(t.map(o=>o.token)),r=a[0]??null,i=new Set(a.flatMap(o=>o.tokens.filter(o=>o.credits?.completed).map(o=>o.curriculum_id))).size;s=r?o(r,l(),i):e(l(),!0)}else s=e(l(),!1);for(const o of s)console.log(o);console.log()}try{const{input:o}=await import("@inquirer/prompts"),{resolveLearnInput:n}=await import("./lib/learn-input.js");console.log(chalk.gray(" Enter a token (or just press Enter to go back).")),console.log();const l=async()=>{try{await o({message:chalk.bold.yellow("Press Enter to return to the menu"),theme:{prefix:"",style:{message:o=>o}}})}catch{}},s=3;for(let r=1;r<=s;r++){const i=await o({message:chalk.bold.cyan("icoa learn>"),theme:{prefix:"",style:{message:o=>o}}}),c=i.trim().toLowerCase();if("ai4ioai"===c||"/ai4ioai"===c){const{runAi4ioaiStandalone:o}=await import("./commands/ai4ioai.js");return await o(),await l(),d({mode:"selection"}),void $()}if(["pandahelpme31","/pandahelpme31","panda help me 31","pandahelpme"].includes(c)){const{runSprint:o}=await import("./commands/sprint.js");return await o(),d({mode:"selection"}),void $()}if("wm"===c||"/wm"===c||c.startsWith("wm ")){const{runWm:o}=await import("./commands/wm.js");return await o(i.trim().split(/\s+/).slice(1).join(" ")||void 0),d({mode:"selection"}),void $()}if("ioailab"===c||"/ioailab"===c){const{runIoailabStandalone:o}=await import("./commands/ioailab.js");return await o(),await l(),d({mode:"selection"}),void $()}if("me"===c||"/me"===c||"profile"===c||"/profile"===c){const o=t.find(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token));if(o){const{fetchLearnProfile:e,renderLearnProfile:t}=await import("./lib/learn-profile.js"),{learnW:n}=await import("./lib/learn-render.js");console.log(chalk.gray(` Loading your profile (${o.token.slice(0,2)}โ€ขโ€ขโ€ขโ€ขโ€ขโ€ข${o.token.slice(-2)})โ€ฆ`));const l=await e(o.token);"ok"===l.kind?t(l.profile,!1,n(),"prompt"):"offline"===l.kind?console.log(chalk.yellow(" Cannot reach the learn server โ€” try me again online.")):console.log(chalk.yellow(` ${"demo"===l.kind?"No profile for a demo token":l.message}`)),console.log()}else console.log(),console.log(chalk.yellow(" No profile yet โ€” open a course with your token first, then type me.")),console.log();r--;continue}const g=c.match(/^\/?(certificate|certificates|cert)(?:\s+(\S+))?$/);if(g){const{certificateLines:e,dropProfileCache:n}=await import("./lib/learn-door.js"),{certifiable:l,certificateIntroLines:s,sameName:a,issueCertificate:i,announceCertificate:c}=await import("./lib/learn-certificate.js"),{fetchProfilesForLocalTokens:y}=await import("./lib/learn-door.js"),d=await y(t.map(o=>o.token)),m=d[0]??null,u=new Set,p=d.flatMap(o=>l(o)).filter(o=>!u.has(o.curriculum_id)&&u.add(o.curriculum_id)),h=(g[2]??"").toLowerCase();console.log();const f=h?p.find(o=>o.curriculum_id.toLowerCase()===h||o.curriculum_id.toLowerCase().startsWith(h)):1===p.length?p[0]:void 0;if(0===p.length||!f&&!h){for(const o of e(m,!1))console.log(o);p.length>1&&console.log(chalk.gray(" type ")+chalk.bold.green("certificate <track>")+chalk.gray(" to issue one.")),console.log(),r--;continue}if(!f){console.log(chalk.yellow(` No finished track matches "${h}". `)+chalk.gray("Finished: "+p.map(o=>o.curriculum_id).join(", "))),console.log(),r--;continue}for(const o of s(f,!1))console.log(o);console.log();const w=async e=>(await o({message:chalk.bold.cyan(e),theme:{prefix:"",style:{message:o=>o}}})).trim(),b=await w("Name on the certificate:");if(!b){console.log(chalk.gray(" Cancelled โ€” nothing issued.")),console.log(),r--;continue}if(!a(b,await w("Type it once more:"))){console.log(chalk.yellow(" The two names differ โ€” nothing issued. Type certificate to try again.")),console.log(),r--;continue}console.log(chalk.gray(" Issuingโ€ฆ (the name is sent once, never stored)")),c(await i(f.token,f.curriculum_id,b),!1),n(),r--;continue}const y=c.match(/^\/?(story|credits)(?:\s+(\S+))?$/);if(y){const{fetchLearnProfile:o}=await import("./lib/learn-profile.js"),{buildCreditLines:e,rollCredits:n,storyListLines:l}=await import("./lib/learn-credits.js"),{learnW:s}=await import("./lib/learn-render.js"),a=t.find(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token));if(console.log(),a){const r=await o(a.token,"credits"===y[1]?"credits":"story");if("ok"!==r.kind)console.log(chalk.yellow(" Cannot reach the learn server โ€” try story again online."));else{const o=(y[2]??"").toLowerCase(),a=r.profile;let i;if(o){const e=Number(o);i=Number.isInteger(e)&&e>=1&&e<=a.tokens.length?a.tokens[e-1]:a.tokens.find(e=>e.curriculum_id.toLowerCase()===o||e.curriculum_id.toLowerCase().startsWith(o))}else"credits"===y[1]&&(i=a.tokens.find(o=>o.credits?.completed));if(i){if(await n(e(i,a,i.curriculum_id,{},!1,s(),!1),()=>!1,180),i.credits?.completed&&!i.credits.credits_rolled_at){const{postCreditsRolled:o}=await import("./lib/learn-profile.js");o(i.token,i.curriculum_id)}}else{o&&console.log(chalk.yellow(` No story for "${o}".`));for(const o of l(a,!1))console.log(o);const e=new Set(a.tokens.map(o=>o.token.toUpperCase())),n=t.filter(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token)&&!e.has(o.token.toUpperCase()));n.length>0&&console.log(chalk.gray(` +${n.length} more course${1===n.length?"":"s"} on this computer not linked yet โ€” open one and type `)+chalk.bold.green("link")+chalk.gray(" to join them."))}}}else console.log(chalk.yellow(" No story yet โ€” open a course with your token first."));console.log(),r--;continue}const{FOCUS_LOG_RE:m,fetchFocusLog:u,renderFocusLog:p}=await import("./lib/learn-focus-log.js");if(m.test(c)){const o=t.find(o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o.token)&&!/DEMO01$/i.test(o.token));if(console.log(),o){const{detectCaps:e}=await import("./lib/render-card.js"),t=await u(o.token);if("ok"===t.kind)for(const o of p(t.log,!1,"T0"===e().tier,"Enter to go back"))console.log(o);else console.log(chalk.yellow("offline"===t.kind?" Offline โ€” the focus log lives on the server; try again when connected.":"demo"===t.kind?" Demo tokens are shared โ€” no focus log. Use your own token.":` Could not load the focus log: ${t.message}`));console.log()}else console.log(chalk.yellow(" No focus log yet โ€” open a course with your token first, then type focus log.")),console.log();r--;continue}const h=c.match(/^\/?(focus|timer)(?:\s+(.*))?$/);if(h){const{FOCUS_MAX:o,FOCUS_MIN:e,FOCUS_STEP:t,getStudyTimer:n,parseFocusMinutes:l}=await import("./lib/learn-study-timer.js"),s=n(),a=(h[2]??"").trim();if(console.log(),s.showPending());else if("off"===a||"stop"===a||"end"===a||"cancel"===a)s.stop()?(await new Promise(o=>setTimeout(o,300)),s.showPending()):console.log(chalk.gray(" No focus session running. Start one: ")+chalk.bold.green("focus 30"));else if(s.active)console.log(chalk.yellow(" โฑ ")+chalk.white(`focus running ยท ${s.remainingMin()} min left`)+chalk.gray(" ยท paste a token and keep going, or ")+chalk.bold.green("focus off"));else if(""===a||"?"===a||"help"===a)console.log(chalk.bold.white(" โฑ Focus session")),console.log(chalk.gray(` How long? (${e}โ€“${o}, steps of ${t}) e.g. `)+chalk.bold.green("focus 30")),console.log(chalk.gray(" Start it here, then open any course โ€” every course you visit counts."));else{const n=l(a);if(n){if("ok"!==n.note){const l="min"===n.note?`min is ${e}`:"max"===n.note?`max is ${o}`:`rounded to the nearest ${t}`;console.log(chalk.gray(` you typed ${a} โ†’ ${l}, using ${n.min}`))}s.start(n.min),console.log(chalk.yellow(" โฑ ")+chalk.bold.white(`Focus ${n.min} min โ€” go`)+chalk.gray(" ยท now paste your token (any course counts) ยท soft reminder every 10 min ยท end early: ")+chalk.bold.green("focus off"))}else console.log(chalk.yellow(` Didn't understand "${a}". `)+chalk.gray("Type minutes, e.g. ")+chalk.bold.green("focus 30"))}console.log(),r--;continue}let f=n(i);if("back"===f.kind)break;if("continue"===f.kind){if(0===t.length){if(console.log(),console.log(chalk.yellow(" Nothing to continue โ€” no previous session on this computer.")),console.log(chalk.gray(" Paste your cohort token to start.")),console.log(),r===s){await l();break}continue}const{which:o}=f;let e=t[0];if("all"===o){console.log(),a(!0),console.log(),r-=1;continue}if("number"==typeof o){if(o<1||o>t.length){if(console.log(),console.log(chalk.yellow(` You have ${t.length} course${t.length>1?"s":""} in progress โ€” pick 1${t.length>1?`-${t.length}`:""}, or type part of its name.`)),console.log(),r===s){await l();break}continue}e=t[o-1]}else if("string"==typeof o){const n=t.filter(e=>e.curriculumId.toLowerCase().includes(o)||e.token.toLowerCase().includes(o));if(1!==n.length){if(console.log(),console.log(chalk.yellow(0===n.length?` No course in progress matches "${o}".`:` "${o}" matches ${n.length} of your courses โ€” be more specific, or use its number.`)),console.log(),a(!0),console.log(),r===s){await l();break}continue}e=n[0]}f={kind:"token",token:e.token}}if("ambiguous"===f.kind||"unknown"===f.kind){if(console.log(),console.log(chalk.yellow(` ${f.hint}`)),console.log(),r===s){console.log(chalk.gray(` That was attempt ${s} of ${s} โ€” going back to the menu.`)),console.log(chalk.gray(" Your token comes from your country team leader.")),console.log(),await l();break}continue}if(f.from){const{loadCurriculumById:o}=await import("./lib/learn-curricula.js");if(!await o(f.token,f.token)){if(console.log(),console.log(chalk.yellow(` "${f.from}" is not a token.`)),console.log(chalk.gray(" Paste the token your team leader gave you (2 letters + 8 characters).")),console.log(),r===s){await l();break}continue}}if(!/^[A-Z0-9]+DEMO01$/i.test(f.token)&&/^[A-Z]{2}[A-Z0-9]{8}$/i.test(f.token)){console.log(),console.log(chalk.gray(" Checking tokenโ€ฆ"));const{validateEAToken:o}=await import("./lib/learn-curricula.js"),e=await o(f.token);if(!e.ok){if(console.log(),console.log(chalk.red(` โœ— Token check failed: ${e.message||"validation failed"}`)+(e.code?chalk.gray(` [${e.code}]`):"")),"device_bound"===e.code?(console.log(chalk.gray(" This learn token is bound to the first computer it was used on,")),console.log(chalk.gray(" and this is a different computer. Ask the coordinator who issued")),console.log(chalk.gray(" it to move it to this device, then try again."))):"expired"===e.code?console.log(chalk.gray(" This learn token has expired โ€” ask your coordinator for a new one.")):(console.log(chalk.gray(" Possible causes:")),console.log(chalk.gray(" ยท Typo in token (check 0/O, 1/I/L, V/U)")),console.log(chalk.gray(" ยท Token expired or revoked")),console.log(chalk.gray(" ยท Network down (check connection)"))),console.log(),r<s){console.log(chalk.gray(" Try again โ€” or press Enter to go back.")),console.log();continue}await l();break}}console.log(),console.log(chalk.gray(" Opening ")+chalk.bold.cyan("learn")+chalk.gray(`: ${f.token}`)),console.log(),d({mode:"selection"}),process.env.ICOA_LEARN_EMBEDDED="1";const{setLearnSessionStarted:w}=await import("./lib/learn-outcome.js");w(!1);try{await e.parseAsync(["node","icoa","learn",f.token])}catch(o){console.log(),console.log(chalk.red(` โœ— learn failed to start: ${o instanceof Error?o.message:String(o)}`)),console.log()}finally{delete process.env.ICOA_LEARN_EMBEDDED}await l();break}}catch(o){n("learn-token-prompt-cancel",o instanceof Error?`${o.name}: ${o.message}`:String(o))}return d({mode:"selection"}),void $()}"organizer"===ne?(console.log(chalk.yellow.bold(" [National/Regional Partner]")),console.log(),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘")),console.log(chalk.bold.white(" โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘")),console.log(chalk.bold.white(" โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•")),console.log(),console.log(chalk.yellow(" International Cyber Olympiad in AI 2026")),console.log(chalk.bold.magenta(" The World's First AI-Native CLI Operating System")),console.log(chalk.bold.magenta(" for Cybersecurity & AI Security Competition")),console.log(chalk.bold.magenta(" and Olympiad for K-12")),console.log(chalk.gray(" Sydney, Australia ยท Jun 27 - Jul 2, 2026")),console.log(),console.log(chalk.white(" Vision")),console.log(chalk.gray(" Building a global pipeline for youth cyber & AI")),console.log(chalk.gray(" security talent through education and competition.")),console.log(),console.log(chalk.white(" Capacity")),console.log(chalk.gray(" 15,000+ concurrent online examinations")),console.log(chalk.gray(" National selection, training, and education support")),console.log(),console.log(chalk.white(" Olympic Spirit")),console.log(chalk.gray(" Excellence ยท Friendship ยท Respect")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" New country accreditation & support:")),console.log(chalk.cyan(" australia@icoa2026.au")),console.log(chalk.cyan(" accreditation@icoa2026.au")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(),i?(console.log(chalk.green(` Logged in as ${r.userName}`)),console.log(chalk.white(" exam list")+chalk.gray(" Manage exams")),console.log(chalk.white(" logout")+chalk.gray(" Disconnect"))):console.log(chalk.white(" join <url>")+chalk.gray(" Connect to manage exams")),console.log(),A(),console.log()):(console.log(` ${chalk.cyan.bold("๐Ÿ† ICOA 2026 ยท International Olympiad")}`),console.log(),E&&!w()?(console.log(chalk.red(" Token was activated on a different device.")),console.log(chalk.gray(" Contact organizer for assistance.")),console.log()):i?(console.log(chalk.green.bold(` Welcome back, ${r.userName}!`)),console.log(chalk.gray(` Connected to ${r.ctfdUrl}`)),console.log(chalk.gray(" Not you? Type ")+chalk.cyan("logout")+chalk.gray(" to switch accounts")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" Ready to compete? Start here:")),console.log(),console.log(chalk.bold.cyan(" challenges")+chalk.gray(" Browse challenges by category")),console.log(chalk.white(" status")+chalk.gray(" Your score & timer")),console.log(chalk.white(" scoreboard")+chalk.gray(" Live rankings")),console.log(chalk.white(" memo")+chalk.gray(" Report an issue to organizers (one-way)")),console.log(),console.log(chalk.gray(" Tool environment:")),console.log(chalk.white(" env")+chalk.gray(" See which of the 110 CTF tools are installed")),console.log(chalk.white(" env setup")+chalk.gray(" Install anything missing (~5 min, one-time)")),console.log(chalk.bold.yellow(" โ˜… ")+chalk.bold.cyan("man <tool>")+chalk.gray(" How to USE a tool (steghide, nmapโ€ฆ) ยท ")+chalk.cyan("man tools")+chalk.gray(" = list")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.gray(" Tip: ")+chalk.cyan("help")+chalk.gray(" ยท ")+I()+chalk.gray(" ยท ")+chalk.cyan("Ctrl+C")+chalk.gray(" pauses ยท ")+chalk.cyan("quit")+chalk.gray(" closes")),console.log()):E?(Po(Zo)||_o(Zo,{recursive:!0}),console.log(chalk.green.bold(" Welcome, competitor!")),console.log(chalk.gray(` Workspace: ${Zo}`)),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" Get started:")),console.log(),console.log(chalk.white(" Step 1 ")+chalk.bold.cyan("join <url>")+chalk.gray(" Connect to competition server")),console.log(chalk.white(" Step 2 ")+chalk.bold.cyan("challenges")+chalk.gray(" Browse & solve challenges")),console.log(chalk.white(" Step 3 ")+chalk.bold.cyan("ai4ctf")+chalk.gray(" Ask AI when stuck")),console.log(),console.log(chalk.gray(" Before Step 1 โ€” make sure your tools are ready:")),console.log(chalk.white(" env")+chalk.gray(" See which of the 110 CTF tools are installed")),console.log(chalk.white(" env setup")+chalk.gray(" Install anything missing (~5 min, one-time)")),console.log(chalk.bold.yellow(" โ˜… ")+chalk.bold.cyan("man <tool>")+chalk.gray(" How to USE a tool (steghide, nmapโ€ฆ) ยท ")+chalk.cyan("man tools")+chalk.gray(" = list")),console.log(),console.log(chalk.gray(" Also: ")+chalk.white("help")+chalk.gray(" all commands")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.gray(" Tip: ")+chalk.cyan("Ctrl+C")+chalk.gray(" pauses ยท ")+I()+chalk.gray(" ยท ")+chalk.cyan("quit")+chalk.gray(" closes CLI")),console.log()):(console.log(chalk.bold.yellow(" ๐Ÿ† You reached the finals tier.")),console.log(chalk.gray(" Full sandbox ยท 110 CTF tools ยท Sydney 2026 ยท this is where finalists compete.")),console.log(),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.white(" To begin, activate your competition token:")),console.log(),console.log(chalk.bold.cyan(" activate <token>")),console.log(),console.log(chalk.gray(" While waiting, explore:")),console.log(chalk.white(" ref linux")+chalk.gray(" Quick reference for Linux")),console.log(chalk.white(" ref web")+chalk.gray(" Quick reference for Web")),console.log(chalk.white(" env")+chalk.gray(" See which of the 110 CTF tools are installed")),console.log(chalk.white(" env setup")+chalk.gray(" Install anything missing (~5 min, one-time)")),console.log(chalk.white(" help")+chalk.gray(" All available commands")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€")),console.log(chalk.gray(" Tip: ")+chalk.cyan("Ctrl+C")+chalk.gray(" pauses ยท ")+I()+chalk.gray(" ยท ")+chalk.cyan("quit")+chalk.gray(" closes CLI")),console.log()))}const le=o=>{o.exitOverride(),o.configureOutput({writeErr:o=>{const e=o.replace(/^error:\s*/i,"").trim();e&&console.log(chalk.yellow(` ${e}`))},writeOut:o=>{console.log(o)}});for(const e of o.commands)le(e)};le(e);const se=o({input:process.stdin,output:process.stdout,prompt:Bo(),terminal:!0,completer:Jo});S(se),ko(!1!==y().bracketedPaste);let ae=!1;if(C(!0),wo(),a&&(console.log(),console.log(chalk.yellow(" โฑ A new competition day has started (Sydney time).")),console.log(chalk.gray(" For fairness, yesterdayโ€™s sign-in has been cleared. Type ")+chalk.cyan("join <url>")+chalk.gray(" to sign in with your account.")),console.log()),So()){const o=y().userName||"this account";console.log(),console.log(chalk.yellow(" โš  This machine is signed in as ")+chalk.bold.white(o)+chalk.yellow(".")),console.log(chalk.gray(" Press ")+chalk.cyan("Enter")+chalk.gray(` to continue as ${o}, or type `)+chalk.cyan("logout")+chalk.gray(" to switch accounts.")),"logout"===(await new Promise(o=>{se.question(chalk.white(" > "),e=>o(e.trim()))})).toLowerCase()&&(d({ctfdUrl:"",token:"",sessionCookie:"",userId:null,userName:"",teamId:null,country:""}),console.log(),console.log(chalk.green(" โœ“ Logged out. ")+chalk.gray("Run ")+chalk.cyan("join <url>")+chalk.gray(" to sign in with your own account."))),console.log()}To()&&$o(()=>se.prompt());let re=null;const ie=se.prompt.bind(se);se.prompt=o=>{if(!(O()||L()||P()||M()||U()||No()||F()||(se.setPrompt(Bo()),o)))try{for(const o of oo()){const e="done"===o.status,t=o.cmd.length>40?`${o.cmd.slice(0,37)}โ€ฆ`:o.cmd,n=o.render?"":chalk.gray(" (")+chalk.white(t)+chalk.gray(") โ€” ")+chalk.cyan(`tasks ${o.id}`);if(console.log((e?chalk.green(" โœ“"):chalk.red(" โœ—"))+chalk.white(` background task #${o.id} ${o.status}`)+n),o.render)try{o.render()}catch{}}const o=H();o&&o!==re?(console.log(o),re=o):o||(re=null)}catch{}ie(o)};const ce=z();ce&&(console.log(chalk.cyan(" โ†ป Continue where you left off: ")+chalk.white(ce.label)+(ce.urgent?chalk.yellow(" (exam timer running)"):"")),console.log(chalk.gray(" type ")+chalk.cyan("resume")+chalk.gray(" to jump back in.")),console.log()),se.prompt(),se.on("line",async o=>{if(ae)return;let n=vo(o.trim());if(!n)return se.setPrompt(O()?chalk.magenta("icoa ai4ctf> "):Bo()),void se.prompt();if(/^icoa\s+\S/i.test(n)&&(n=n.replace(/^icoa\s+/i,"")),n.startsWith("/")&&!n.startsWith("//")){const o=n.slice(1).split(/\s+/)[0].toLowerCase(),t=n.slice(1+o.length).trim();if("ai"===o)return ae=!0,await async function(o,e){if(O())return void(o?await j(o):console.log(chalk.gray(" You are already in the AI chat โ€” just type your message.")));if(L())return void(o?await D(o):console.log(chalk.gray(" You are already in the CTF4AI target chat โ€” just type your message.")));if(P())return void(o?await _(o):console.log(chalk.gray(" You are already in the Embodied-AI chat โ€” just type your message.")));fo(o?`/ai ${o}`:"/ai");const t=process.exit;process.exit=()=>{throw new Error(Xo)};try{await e.parseAsync(["node","icoa","ai4ctf"])}catch(o){if(!(o instanceof Error&&o.message===Xo))throw o}finally{process.exit=t}o&&O()&&await j(o)}(t,e),ae=!1,se.setPrompt(O()?chalk.magenta("icoa ai4ctf> "):Bo()),void se.prompt();!(O()||L()||P()||M()||U()||No())&&zo.includes(o)&&(n=n.slice(1))}if("resume"===n.toLowerCase()){const o=z();return o?(fo(`resume โ†’ ${o.command.join(" ")}`),ae=!0,await Vo(e),ae=!1,se.setPrompt(O()?chalk.magenta("icoa ai4ctf> "):Bo()),void se.prompt()):(console.log(),console.log(chalk.gray(" Nothing to resume yet โ€” start with ")+chalk.cyan("learn")+chalk.gray(" (curriculum) or ")+chalk.cyan("demo")+chalk.gray(" (taste).")),console.log(),void se.prompt())}const s=O()||L()||P()||M()||U();if(!s&&("bg"===n.toLowerCase()||/^bg\s/i.test(n))){const o=n.replace(/^bg\s*/i,"").trim();if(!o)return console.log(),console.log(chalk.gray(" Usage: ")+chalk.cyan("bg <command>")+chalk.gray(" โ€” run a non-interactive shell command in the background.")),console.log(chalk.gray(" e.g. ")+chalk.cyan("bg nmap -p- 10.0.0.5")+chalk.gray(" ยท view: ")+chalk.cyan("tasks")),console.log(),void se.prompt();const e=ho(),t=uo(o);po({cwd:e,input:`bg ${o}`,riskFlags:t}),t.length>0&&Y()&&console.log(chalk.yellow(` โš  Action flagged: ${t.join(", ")} โ€” logged.`));const l=J(o,e);return console.log(),console.log(chalk.cyan(` โ–ธ background task #${l.id} started`)+chalk.gray(` (${to()} running)`)),console.log(chalk.gray(" ")+chalk.white(o)),console.log(chalk.gray(" view: ")+chalk.cyan("tasks")+chalk.gray(" ยท output: ")+chalk.cyan(`tasks ${l.id}`)),console.log(),void se.prompt()}if(!s&&("tasks"===n.toLowerCase()||/^tasks\s/i.test(n))){const o=n.replace(/^tasks\s*/i,"").trim(),e=G();if(console.log(),o){const e=K(Number(o));if(!e||Number.isNaN(Number(o)))console.log(chalk.yellow(` No background task #${o}.`)+chalk.gray(" Type ")+chalk.cyan("tasks")+chalk.gray(" to list them."));else{const o="running"===e.status?chalk.yellow:"done"===e.status?chalk.green:chalk.red;console.log(o(` #${e.id} [${e.status}]`)+chalk.white(` ${e.cmd}`)+(null!==e.exitCode?chalk.gray(` (exit ${e.exitCode})`):"")),console.log(chalk.gray(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€"));const t=e.output.trim();if(t)for(const o of t.split("\n"))console.log(chalk.gray(" ")+chalk.white(o));else console.log(chalk.gray(" (no output yet)"))}}else if(0===e.length)console.log(chalk.gray(" No background tasks. Start one with ")+chalk.cyan("bg <command>")+chalk.gray("."));else{console.log(chalk.bold.white(" Background tasks"));for(const o of e){const e="running"===o.status?chalk.yellow("โ—"):"done"===o.status?chalk.green("โœ“"):chalk.red("โœ—"),t=Math.round(((o.endedAt??Date.now())-o.startedAt)/1e3),n=(o.endedAt?`${t}s`:`${t}sโ€ฆ`).padStart(5),l=o.cmd.length>48?`${o.cmd.slice(0,45)}โ€ฆ`:o.cmd;console.log(` ${e} `+chalk.white(`#${o.id}`)+chalk.gray(` ${n} `)+chalk.white(l))}console.log(chalk.gray(" output: ")+chalk.cyan("tasks <id>"))}return console.log(),void se.prompt()}if(!s&&/&\s*$/.test(n)&&/^challenge\s+start\s+/i.test(n)){const o=n.replace(/\s*&\s*$/,"").trim().replace(/^challenge\s+start\s+/i,"").trim().split(/\s+/),e=o.some(o=>"-n"===o||"--new"===o),t=o.find(o=>"-n"!==o&&"--new"!==o);if(!t)return console.log(),console.log(chalk.gray(" Usage: ")+chalk.cyan("challenge start <id> &")),console.log(),void se.prompt();if(!g())return console.log(),console.log(chalk.red(" Not connected. ")+chalk.gray("Run ")+chalk.cyan("join <url>")+chalk.gray(" first.")),console.log(),void se.prompt();fo(`challenge start ${t}${e?" --new":""} & (background)`);const l=V(`challenge start ${t}`,()=>no(t,e),o=>lo(t,o));return console.log(),console.log(chalk.cyan(` โ–ธ background task #${l.id}: `)+chalk.white(`starting ${t}`)+chalk.gray(" โ€” you can keep working; the connection info appears here when it is ready.")),console.log(),void se.prompt()}if(!s&&n.startsWith("#")){const o=n.slice(1).trim();if(!o)return console.log(),console.log(chalk.gray(" Usage: ")+chalk.cyan("#<candidate answer>")+chalk.gray(" โ€” stage a flag/answer WITHOUT submitting it. Review with ")+chalk.cyan("drafts")+chalk.gray(".")),console.log(),void se.prompt();const e=Z(),t=e?.session?.examId??null,l=e?e._lastQ||1:null,s=so(o,t,l);return fo(`draft #${s.id} (not submitted)`),console.log(),console.log(chalk.green(` โœŽ draft #${s.id} saved`)+(l?chalk.gray(` (Q${l})`):"")+chalk.yellow(" โ€” NOT submitted.")),console.log(chalk.gray(" review with ")+chalk.cyan("drafts")+chalk.gray("; when sure, submit it the normal way.")),console.log(),void se.prompt()}if(!s&&("drafts"===n.toLowerCase()||/^drafts\s/i.test(n))){const o=n.replace(/^drafts\s*/i,"").trim().toLowerCase();if("clear"===o){const o=io();return console.log(),console.log(chalk.gray(` Cleared ${o} draft${1===o?"":"s"}.`)),console.log(),void se.prompt()}const e=o.match(/^(?:rm|remove|del|delete)\s+(\d+)$/);if(e){const o=ro(Number(e[1]));return console.log(),console.log(o?chalk.gray(` Removed draft #${e[1]}.`):chalk.yellow(` No draft #${e[1]}.`)),console.log(),void se.prompt()}const t=Z(),l=ao(t?.session?.examId??null);if(console.log(),0===l.length)console.log(chalk.gray(" No drafts yet. Stage a candidate with ")+chalk.cyan("#ICOA{maybe_this}")+chalk.gray(" โ€” it wonโ€™t submit."));else{console.log(chalk.bold.white(" Draft answers")+chalk.gray(" (staged โ€” not submitted)"));for(const o of l){const e=o.q?chalk.cyan(`Q${o.q}`.padStart(4)):chalk.gray(" ยท ");console.log(chalk.gray(` #${o.id}`)+` ${e} `+chalk.white(o.text.length>56?`${o.text.slice(0,53)}โ€ฆ`:o.text))}console.log(chalk.gray(" remove: ")+chalk.cyan("drafts rm <id>")+chalk.gray(" ยท clear all: ")+chalk.cyan("drafts clear"))}return console.log(),void se.prompt()}if("menu"===n||"menu confirm"===n)return Y()&&"menu confirm"!==n?(console.log(),console.log(chalk.yellow(" Real exam active. Progress is auto-saved.")),console.log(chalk.gray(" To return to main menu anyway, type ")+chalk.white("menu confirm")),console.log(),void se.prompt()):void $(se);if(O()){ae=!0;const o=await j(n);return ae=!1,"exit"===o&&se.setPrompt(Bo()),void se.prompt()}if(L()){ae=!0;const o=await D(n);return ae=!1,"exit"!==o&&"solved"!==o||se.setPrompt(Bo()),void se.prompt()}if(P()){ae=!0;const o=await _(n);return ae=!1,"exit"===o&&se.setPrompt(Bo()),se.setPrompt(P()?chalk.bold.cyan("icoa ctf4eai> "):Bo()),void se.prompt()}if(fo(n),"exit"===n)return Z()?(console.log(),console.log(chalk.yellow(" โš  An exam is in progress.")),console.log(chalk.white(" To return to menu without losing progress, type: ")+chalk.bold.cyan("back")),console.log(chalk.white(" To fully close ICOA CLI, type: ")+chalk.bold.cyan("quit")),console.log(chalk.gray(" Your progress is auto-saved either way.")),console.log(),void se.prompt()):(console.log(),console.log(chalk.gray(" ")+chalk.white("exit")+chalk.gray(" returns to the main menu. To fully close ICOA CLI, type ")+chalk.bold.cyan("quit")+chalk.gray(".")),"selection"===ne&&Go(),void se.prompt());if("quit"===n||"q"===n||"quit confirm"===n){const o=Z();return o&&"demo-free"!==o.session.examId&&"quit confirm"!==n?(console.log(),console.log(chalk.yellow(" โš  A real exam is in progress.")),console.log(chalk.gray(" Your answers are auto-saved on the server, but the exam timer keeps ticking")),console.log(chalk.gray(" on the server side even if you close the CLI.")),console.log(),console.log(chalk.white(" To leave the CLI but keep the exam alive, type: ")+chalk.bold.cyan("back")),console.log(chalk.gray(" (recommended โ€” you can resume with ")+chalk.cyan("exam q 1")+chalk.gray(" after relaunching icoa)")),console.log(),console.log(chalk.white(" To really close ICOA CLI, type: ")+chalk.bold.cyan("quit confirm")),console.log(),void se.prompt()):(o&&"demo-free"===o.session.examId&&(console.log(),console.log(chalk.gray(" Demo paused. Resume with: ")+chalk.white("demo")+chalk.gray(" (fresh) or ")+chalk.white("exam q 1")+chalk.gray(" (continue)."))),bo(),xo(),Ao(),eo(),b(),console.log(chalk.gray(" Session saved. Use ")+chalk.white("icoa --resume")+chalk.gray(" to continue.")),co(),void c(0))}if("back"===n){const o=Z(),e=o&&"demo-free"!==o.session.examId,t=o&&"demo-free"===o.session.examId&&(()=>{const e=new Date(o.session.startedAt||0).getTime();return Date.now()-e<18e5})();if(e)console.log(),console.log(chalk.gray(" Exam paused. Your progress is saved.")),console.log(chalk.white(" Resume: exam q 1")+chalk.gray(" ยท ")+chalk.white("exam review")+chalk.gray(" ยท ")+chalk.white("exam submit")),console.log();else if(t){const e=Object.keys(o.answers).length,t=o.session.questionCount;console.log(),console.log(chalk.gray(` Demo paused (${e}/${t} answered). Resume with: `)+chalk.white("exam q 1")),console.log(chalk.gray(" Or type ")+chalk.white("demo")+chalk.gray(" to restart.")),console.log()}else{if(o&&"demo-free"===o.session.examId){const{clearExamState:o}=await import("./lib/exam-state.js");o("demo-free")}const e=y();fetch("https://practice.icoa2026.au/api/icoa/demo-stats",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"post-report-back",lang:e.language||"en",timestamp:(new Date).toISOString()}),signal:AbortSignal.timeout(5e3)}).catch(()=>{}),"selection"===ne?Go():console.log(chalk.gray(" Already at main menu."))}return void se.prompt()}if("help"===n||"?"===n){if(Z()){ae=!0;try{await e.parseAsync(["node","icoa","exam","help"])}catch{}return ae=!1,void se.prompt()}return oe(p(),ne),void se.prompt()}if("man"===n||"manual"===n)return oe(p(),ne),console.log(),console.log(chalk.bold.yellow(" โ˜… Stuck on a tool? ")+chalk.bold.cyan("man <tool>")+chalk.gray(" e.g. ")+chalk.cyan("man steghide")+chalk.gray(" ยท ")+chalk.cyan("man tools")+chalk.gray(" = full list")),void se.prompt();if(/^(?:man|manual)\s+\S/i.test(n))return N(n.replace(/^(?:man|manual)\s+/i,"")),void se.prompt();if("more help"===n.toLowerCase()&&Z()){ae=!0;try{await e.parseAsync(["node","icoa","exam","more-help"])}catch{}return ae=!1,void se.prompt()}if("continue"===n.toLowerCase())return console.log(),console.log(chalk.green.bold(" โ•โ•โ• AI4CTF โ€” AI as Your Teammate โ•โ•โ•")),console.log(),console.log(chalk.white(" In AI4CTF, you solve cybersecurity challenges")),console.log(chalk.white(" with AI by your side.")),console.log(),console.log(chalk.white(" In this demo, your AI teammate gives help at 3 levels:")),console.log(chalk.yellow(" hint a")+chalk.gray(" General guidance")),console.log(chalk.yellow(" hint b")+chalk.gray(" Deep analysis")),console.log(chalk.yellow(" hint c")+chalk.gray(" Critical assist")),console.log(),console.log(chalk.white(" Try it now! Type: ")+chalk.bold.green("ai4ctf")),console.log(chalk.gray(' Chat freely with your AI teammate. Type "exit" when done.')),console.log(),console.log(chalk.gray(" After ai4ctf, try: ")+chalk.bold.red("ctf4ai")+chalk.gray(' โ€” trick the AI into saying "koala"')),console.log(),void se.prompt();if(/^ICOA-[A-Z]{2,3}-\d{1,6}$/i.test(n.trim())){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",n.trim()])}catch{}return ae=!1,void se.prompt()}if(/^[A-Z]{2}[0-9A-HJKMNP-TV-Z]{8}$/i.test(n.trim())){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",n.trim().toUpperCase()])}catch{}return ae=!1,void se.prompt()}const a=n.match(/^exam\s+([A-Z]{2}[0-9A-HJKMNP-TV-Z]{8})$/i);if(a){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",a[1].toUpperCase()])}catch{}return ae=!1,void se.prompt()}const r=n.match(/^exam\s+([A-Z]{2,3})$/i);if(r){ae=!0;try{await e.parseAsync(["node","icoa","exam","list",r[1]])}catch{}return ae=!1,void se.prompt()}const i=n.match(/^exam\s+(\S+)$/i);if(i&&!Ho.has(i[1].toLowerCase())){const o=i[1].toUpperCase(),{normalizeTokenBody:t}=await import("./lib/token-format.js"),n=t(o),l=/^[A-Z]{2}[0-9A-HJKMNP-TV-Z]{8}$/;if(console.log(),l.test(n)){console.log(chalk.yellow(` Corrected look-alike characters: ${o} โ†’ ${n}`)),ae=!0;try{await e.parseAsync(["node","icoa","exam","token",n])}catch{}return ae=!1,void se.prompt()}return console.log(chalk.red(` โœ— Not a valid exam token: ${o}`)),console.log(),console.log(chalk.gray(" An exam token is ")+chalk.bold.white("2 letters + 8 characters")+chalk.gray(" (e.g. ")+chalk.bold.yellow("AUHXP7SWMM")+chalk.gray(`) โ€” yours is ${o.length}.`)),console.log(chalk.gray(" Check for 0/O, 1/I/L, V/U mix-ups, or ask your country team leader.")),console.log(),console.log(chalk.gray(" No token yet? Try ")+chalk.bold.green("demo")+chalk.gray(" (free practice paper) or ")+chalk.bold.green("exam nations")+chalk.gray(" to see participating countries.")),console.log(),void se.prompt()}if("clear"===n||"cls"===n)return console.clear(),void se.prompt();if("news"===n)return To()?Io():console.log(chalk.gray(" No competition joined. Use ")+chalk.white("join <url>")+chalk.gray(".")),void se.prompt();if("memo"===n){if(!To())return console.log(chalk.gray(" Join a competition first: ")+chalk.white("join <url>")),void se.prompt();ae=!0;try{await Lo()}catch{}return void(ae=!1)}const d=Oo()||Eo(y().userName||"");if("jury"===n&&d){ae=!0;try{await Do()}catch{}return void(ae=!1)}if(d&&Oo()&&"scoreboard"===n.split(/\s+/)[0]){ae=!0;try{const o=await jo();if(console.log(),0===o.length)console.log(chalk.gray(" Scoreboard is empty."));else{console.log(chalk.bold.white(" Scoreboard"));for(const e of o.slice(0,50))console.log(chalk.gray(` ${String(e.pos).padStart(3)}. `)+chalk.white(e.name.padEnd(28).slice(0,28))+chalk.cyan(String(e.score)))}console.log()}catch{}return ae=!1,void se.prompt()}if(d&&So()){const o=n.split(/\s+/)[0];if(["challenges","open","submit","hint"].includes(o))return console.log(),console.log(chalk.yellow(" Team-leader account โ€” the challenge bracket is not available here.")),console.log(chalk.gray(" Available: ")+chalk.white("scoreboard")+chalk.gray(" ยท ")+chalk.white("news")+chalk.gray(" ยท ")+chalk.white("jury")+chalk.gray(" ยท ")+chalk.white("time")+chalk.gray(" ยท ")+chalk.white("status")+chalk.gray(" ยท ")+chalk.white("logout")),console.log(),void se.prompt()}if(n.startsWith("activate ")){const o=n.slice(9).trim(),e=await h(o);return"ok"===e?console.log(chalk.green(" Access granted! Token bound to this device.")):"network"===e?(console.log(),console.log(chalk.red(" Could not reach the activation server.")),console.log(chalk.gray(" Activation needs internet once โ€” check your connection to ")+chalk.cyan("practice.icoa2026.au")+chalk.gray(" and run the same command again."))):"already_bound"===e?(console.log(),console.log(chalk.red(" Token already activated on a different device.")),console.log(chalk.gray(" Each token binds to the first device that uses it. If you lost the device,")),console.log(chalk.gray(" contact your proctor to have the token re-issued for a new device."))):(console.log(),console.log(chalk.red(" Token not recognized.")),console.log(chalk.gray(" Possible reasons:")),console.log(chalk.white(" โ€ข ")+chalk.gray("Typo โ€” access tokens are case-insensitive and look like ")+chalk.cyan("ICOA-XXXX-XXXX-XXXX")+chalk.gray(" (4-char hex groups, e.g. ICOA-385E-27F2-B21B)")),console.log(chalk.white(" โ€ข ")+chalk.gray("Expired โ€” ask your proctor or organizer for a fresh token")),console.log(chalk.white(" โ€ข ")+chalk.gray("Network โ€” verify connection to ")+chalk.cyan("practice.icoa2026.au")),console.log(chalk.gray(" Still stuck? type ")+chalk.cyan("help")+chalk.gray(" or try ")+chalk.cyan("exam demo")+chalk.gray(" for a free practice round."))),console.log(),void se.prompt()}if("activate"===n)return console.log(chalk.gray(" Usage: ")+chalk.white("activate <token>")),console.log(),void se.prompt();const m=Z();if(m){const o=n.toUpperCase().trim(),t=o=>{const e=m.questions.find(e=>e.number===o);return!!e&&("ai4ctf"===e.type||"ctf4ai"===e.type||e.options&&!e.options.A&&!e.options.B)},l=o=>{const e=m.questions.find(e=>e.number===o);return"short_answer"===e?.type},s=o=>{const e="demo-free"!==m.session.examId,t=m.questions.find(e=>e.number===o),n=Q(t?.type,e);console.log(),console.log(chalk.yellow(` Q${o} is a practical question โ€” letters (A/B/C/D) don't apply here.`)),n?(console.log(chalk.white(" Enter the AI chat for this question: ")+chalk.bold.cyan(n)),console.log(chalk.gray(" Or submit a flag directly: ")+chalk.green(`exam answer ${o} ICOA{your_flag}`))):console.log(chalk.gray(" Submit a flag: ")+chalk.green(`exam answer ${o} ICOA{your_flag}`)),console.log()};if(/^[ABCDE]$/.test(o)){const n=m._lastQ||1;if(t(n))return s(n),void se.prompt();if(l(n))return console.log(),console.log(chalk.yellow(` Q${n} is a short-answer question โ€” type a number, not a letter.`)),console.log(chalk.gray(" Example: ")+chalk.green("42")+chalk.gray(" (or ")+chalk.green(`exam answer ${n} 42`)+chalk.gray(")")),console.log(),void se.prompt();ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(n),o])}catch{}return ae=!1,void se.prompt()}if(/^-?\d+$/.test(o)){const t=m._lastQ||1;if(l(t)){ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(t),o])}catch{}return ae=!1,void se.prompt()}}const a=o.match(/^(\d+)\s+([ABCDE]|-?\d+)$/);if(a){const o=parseInt(a[1],10);if(t(o))return s(o),void se.prompt();ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",a[1],a[2]])}catch{}return ae=!1,void se.prompt()}}const u=n.split(/\s+/)[0].toLowerCase(),k=/^python3?(\.\d+)?$/.test(u),x="ls"===u||"pwd"===u||"tmux"===u,v=n.startsWith("!")||u.startsWith("!")||k||x,C=new Set(["nano","vi","vim","emacs","pico","ed","code","cat","less","more","head","tail","ls","pwd","cd","base64","xxd","hexdump","od","openssl","md5sum","sha256sum","grep","find","awk","sed","strings","file","curl","wget","nc","ping","nmap","echo","bash","sh","zsh","pip","pip3","node","npm"]),A=()=>{console.log(chalk.gray(" Shell commands need ")+chalk.bold.cyan("!")+chalk.gray(" prefix. Try: ")+chalk.bold.cyan(`!${n}`)),console.log()};if("py"===u||"pylist"===u)return console.log(chalk.yellow(` ${u} is the learn-card Python scratchpad โ€” it lives inside learn.`)),console.log(chalk.gray(" Open your course first: ")+chalk.bold.cyan("learn <TOKEN>")+chalk.gray(" (or bare ")+chalk.bold.cyan("learn")+chalk.gray(" for the demo), then type ")+chalk.bold.cyan("py"===u?"/py":"/pylist")+chalk.gray(" on any card.")),console.log(),void se.prompt();if("embodied"===ne&&!v&&!["doctor","demo2","learn","exam","ctf4eai","ctf4vla","eai","arena","lang","ref","setup","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(u))return C.has(u)?(A(),void se.prompt()):(console.log(chalk.gray(" Not available in Embodied AI Security mode.")),console.log(chalk.white(" Try ")+chalk.bold.cyan("demo2")+chalk.gray(" (intro) ยท ")+chalk.bold.cyan("learn")+chalk.gray(" (curriculum) ยท ")+chalk.bold.cyan("exam <PD-token>")+chalk.gray(" (Paper D)")),console.log(),void se.prompt());if("selection"===ne&&!v&&!["doctor","exam","demo","demo2","demo4","demo5","gfssm","retry","nations","next","prev","continue","setup","lang","ref","ai4ctf","ctf4ai","mark","unmark","review","submit","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(u)){if(C.has(u))return A(),void se.prompt();if(l().includes(u))console.log(chalk.gray(` ${u} isn't available on this screen.`));else{console.log(chalk.yellow(` Unknown command: ${u}`));const o=nearestCommand(u);o&&console.log(chalk.gray(" Did you mean: ")+chalk.bold.cyan(o)+chalk.gray("?"))}if(m){const o=m._lastQ||1;console.log(chalk.white(` Resume exam: exam q ${o}`)+chalk.gray(" ยท ")+chalk.white("A/B/C/D")+chalk.gray(" to answer"))}else console.log(chalk.gray(" Try: ")+chalk.bold.cyan("learn <TOKEN>")+chalk.gray(" ยท ")+chalk.bold.cyan("exam <CC>xxxxxxxx")+chalk.gray(" ยท ")+chalk.bold.cyan("demo")+chalk.gray(" ยท ")+chalk.bold.cyan("help")+chalk.gray(" ยท ")+chalk.bold.cyan("menu"));return console.log(),void se.prompt()}if("organizer"===ne&&!["doctor","join","exam","demo","retry","next","prev","logout","setup","lang","ref","ctf","mark","unmark","review","submit","tmux"].includes(u))return console.log(chalk.gray(" Not available in Organizer mode. Switch via: setup")),console.log(),void se.prompt();if(!("olympiad"!==ne||p()&&w()||f(u)))return console.log(chalk.yellow(" Restricted mode. ")+chalk.gray("Enter your access token:")),console.log(chalk.white(" activate <token>")),console.log(),console.log(chalk.gray(" Free commands: ")+chalk.white("ref [topic]")+chalk.gray(", ")+chalk.white("help")+chalk.gray(", ")+chalk.white("exit")),console.log(),void se.prompt();if(!l().includes(u)){if("tmux"===u)try{t("command -v tmux",{stdio:"ignore"})}catch{return console.log(chalk.yellow(" tmux is not installed yet.")),console.log(chalk.gray(" Install it with ")+chalk.bold.cyan("env setup")+chalk.gray(" (full toolkit) or ")+chalk.bold.cyan("darwin"===process.platform?"brew install tmux":"sudo apt install tmux")+chalk.gray(".")),console.log(),void se.prompt()}if(Yo.has(u))return console.log(chalk.yellow(` "${u}" is a shell command โ€” the ICOA prompt isn't a shell.`)),console.log(chalk.gray(" In real-exam mode, prefix with ! to run inside the sandbox: ")+chalk.cyan(`!${n}`)),console.log(),void se.prompt();if(/(?:^|\s)(?:\/(?!home\/|Users\/|tmp\/)|\.\.\/|~\/)/.test(n)&&!n.startsWith("cd ")){const o=/(?:^|\s)\/(?!home\/\w+\/icoa-workspace|Users\/\w+\/icoa-workspace|tmp\/)/.test(n),e=/\.\./.test(n);if(o||e)return console.log(chalk.red(" Blocked: access outside workspace is not allowed.")),console.log(chalk.gray(` Workspace: ${Zo}`)),console.log(),void se.prompt()}let o=n.startsWith("!")?n.slice(1).trim():n;if("darwin"===process.platform){const e="/opt/homebrew/opt/python@3.12/bin/python3.12";o=o.replace(/^python3?\s/,`${e} `).replace(/^(python3|python)$/,e)}else if("win32"===process.platform){const e=(()=>{try{return t("py -3 --version",{stdio:["ignore","ignore","ignore"],timeout:1500}),"py -3"}catch{}return"python"})();o=o.replace(/^python3?(\.\d+)?\s/,`${e} `).replace(/^python3?(\.\d+)?$/,e)}else{const e=(()=>{try{return t("which python3.12",{stdio:"ignore"}),"python3.12"}catch{return"python3"}})();o=o.replace(/^python\s/,`${e} `).replace(/^python$/,e)}const e=ho(),l=uo(n);po({cwd:e,input:n,riskFlags:l}),l.length>0&&Y()&&(console.log(chalk.yellow(` โš  Action flagged: ${l.join(", ")} โ€” logged.`)),console.log()),/^(\S*python3?(\.\d+)?)\s*$/.test(o)&&(o=`PYTHONSTARTUP="${function(){const o=Uo(Ro(),".icoa");Po(o)||_o(o,{recursive:!0});const e=Uo(o,"python-startup.py");let t="";if(Po(e))try{t=Mo(e,"utf-8")}catch{}return t!==qo&&Fo(e,qo),e}()}" ${o}`,console.log(),console.log(chalk.cyan(" โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”")),console.log(chalk.bold.white(" Python ready โ€” ICOA exam toolkit pre-loaded")),console.log(chalk.cyan(" โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”")),console.log(),console.log(chalk.white(" Already imported: ")+chalk.gray("base64, struct, hashlib, re, json, binascii")),console.log(chalk.white(" Also available: ")+chalk.gray("requests, bs4, numpy, PIL.Image, AES, pad/unpad, xor, p32/u32/p64/u64")),console.log(),console.log(chalk.yellow(" Quick examples:")),console.log(chalk.gray(' base64.b64decode("aGVsbG8=") ')+chalk.gray("# decode base64")),console.log(chalk.gray(' bytes.fromhex("48656c6c6f") ')+chalk.gray("# hex โ†’ bytes")),console.log(chalk.gray(' "ICOA{x}".encode() ')+chalk.gray("# str โ†’ bytes")),console.log(chalk.gray(" [chr(c) for c in [73,67,79,65]] ")+chalk.gray("# ASCII codes")),console.log(chalk.gray(' xor(bytes.fromhex("0a2b"), b"IC") ')+chalk.gray("# pwntools XOR")),console.log(),console.log(chalk.gray(" Exit: ")+chalk.white("exit()")+chalk.gray(" or Ctrl-D")),console.log(chalk.cyan(" โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”")),console.log()),ae=!0;try{await mo()&&await go()?await yo(o,se):await Ko(o,se,e)}catch{console.log(chalk.yellow(` Command failed: ${u}`))}return ae=!1,console.log(),void se.prompt()}ae=!0;const I=n.trim(),T=I.toLowerCase();let S,E=null,F="";if(m)if("submit"===T)E="final";else if(T.startsWith("submit ")){let o=I.slice(7).trim();/^submit\s+/i.test(o)&&(o=o.replace(/^submit\s+/i,"").trim()),o=o.replace(/^["'`]+|["'`]+$/g,"").trim(),o&&/^ICOA\{[^}]*\}?$/i.test(o)?(E="flag",F=o):o&&/^[ABCDE]$/i.test(o)&&(E="flag",F=o.toUpperCase())}else/^ICOA\{[^}]+\}$/i.test(I)&&(E="flag",F=I);S="final"===E?["exam","submit"]:"flag"===E?["exam","answer",String(m?._lastQ||1),F]:mapCommand(n);const R="ctf"===S[0]&&"join"===S[1];R&&se.pause(),process.exit=()=>{throw new Error(Xo)};try{await e.parseAsync(["node","icoa",...S])}catch(o){const e=o instanceof Error?o.message:String(o);if(e===Xo);else if(e.includes("commander.unknownCommand")){const o=nearestCommand(u.split(/\s+/)[0]||u);console.log(chalk.yellow(` Unknown command: ${u}.`)),o&&console.log(chalk.gray(" Did you mean: ")+chalk.bold.cyan(o)+chalk.gray("?")),console.log(chalk.gray(" Type ")+chalk.cyan("help")+chalk.gray(" for the full command list."))}else e.includes("commander.missingArgument")||"commander.missingArgument"===o?.code?"submit"===u||"flag"===u?(console.log(chalk.yellow(" Incomplete โ€” usage: ")+chalk.cyan("submit <challenge#> <flag>")),console.log(chalk.gray(" Put the number AND the flag on one line, e.g. ")+chalk.cyan("submit 44 pecan{...}"))):(console.log(chalk.yellow(` Incomplete command: ${u}`)),console.log(chalk.gray(" Type ")+chalk.cyan("help")+chalk.gray(" for usage."))):e.includes("commander.")||(e.includes("fetch failed")||e.includes("ECONNREFUSED")||e.includes("ETIMEDOUT"))&&console.log(chalk.yellow(" Network error. Check your connection."))}finally{process.exit=c,ae=!1,R&&se.resume()}O()?se.setPrompt(chalk.magenta("icoa ai4ctf> ")):L()?se.setPrompt(chalk.red("icoa ctf4ai> ")):P()&&se.setPrompt(chalk.bold.cyan("icoa ctf4eai> ")),console.log(),se.prompt()}),se.on("SIGINT",()=>{if(console.log(),O()||L())console.log(chalk.yellow(" Ctrl+C did not close ICOA CLI โ€” you are still in the AI chat.")),console.log(chalk.white(" Type ")+chalk.bold.cyan("exit")+chalk.white(" to leave the chat and return to the menu."));else if(Z()){const o="demo-free"!==Z().session.examId;console.log(chalk.yellow(" Ctrl+C did NOT close ICOA CLI.")),console.log(chalk.gray(` Your ${o?"exam":"demo"} is paused and every answer is auto-saved.`)),console.log(),console.log(chalk.white(" Resume: ")+chalk.cyan("exam q 1")+chalk.gray(" ยท Back to menu: ")+chalk.cyan("back")+chalk.gray(" ยท Close CLI: ")+chalk.cyan(o?"quit confirm":"quit"))}else console.log(chalk.yellow(" Ctrl+C did not close ICOA CLI โ€” you are still at the ")+chalk.cyan("icoa>")+chalk.yellow(" prompt.")),console.log(chalk.gray(" Keep typing โ€” ")+chalk.cyan("help")+chalk.gray(" lists commands. (Only ")+chalk.cyan("quit")+chalk.gray(" or Ctrl+D actually close the CLI.)"));console.log(),se.prompt()}),se.on("close",()=>{n("main-rl-close",`stdin.isTTY=${!0===process.stdin.isTTY}`),console.log(),console.log(chalk.gray(" input closed โ€” leaving icoa. Run icoa --resume to continue.")),bo(),xo(),Ao(),eo(),b(),co(),c(0)}),"1"===process.env.ICOA_AUTO_RESUME&&(delete process.env.ICOA_AUTO_RESUME,z()&&(ae=!0,await Vo(e),ae=!1,se.setPrompt(O()?chalk.magenta("icoa ai4ctf> "):Bo()),se.prompt()))}function Ko(o,t,n){return new Promise(l=>{const s=process.stdin,a=!!s.isTTY&&!!s.isRaw;if(t.pause(),s.isTTY&&"function"==typeof s.setRawMode)try{s.setRawMode(!1)}catch{}const r=e(o,{shell:!0,stdio:"inherit",cwd:n||process.cwd()}),i=()=>{if(s.isTTY&&"function"==typeof s.setRawMode&&a)try{s.setRawMode(!0)}catch{}Co(),t.resume(),l()};r.on("close",e=>{if(127===e){const e=nearestCommand(o.trim().split(/\s+/)[0]??"");e&&console.log(chalk.gray(" Did you mean: ")+chalk.bold.cyan(e)+chalk.gray("?"))}i()}),r.on("error",i)})}export function mapCommand(o){const e=o.split(/\s+/),t=e[0].toLowerCase(),n=e.slice(1);if("aienv"===t&&["run","python","py"].includes((n[0]??"").toLowerCase()))return E(o);if(("submit"===t||"flag"===t)&&n.length>=2)return["ctf","submit",n[0],n.slice(1).join(" ").trim().replace(/^["'`]+|["'`]+$/g,"")];if("connect"===t&&n.length>=2){const e=E(o);return["connect",e[1]??n[0],e.slice(2).join(" ")]}return a(t,n)||[t,...n]}function oe(o,e="olympiad"){if(console.log(),"selection"===e||"organizer"===e)return console.log(chalk.bold.white(" Exam")),console.log(chalk.white(" join <url> ")+chalk.gray("Connect to exam server")),console.log(chalk.white(" exam list ")+chalk.gray("Available exams")),console.log(chalk.white(" exam start <id> ")+chalk.gray("Begin an exam")),console.log(chalk.white(" exam q [n] ")+chalk.gray("View questions")),console.log(chalk.white(" exam answer <n> <X> ")+chalk.gray("Answer question")),console.log(chalk.white(" exam review ")+chalk.gray("Review all answers")),console.log(chalk.white(" exam submit ")+chalk.gray("Submit for grading")),console.log(chalk.white(" exam result ")+chalk.gray("View your score")),console.log(),console.log(chalk.bold.white(" System")),console.log(chalk.white(" ref [topic] ")+chalk.gray("Quick reference")),console.log(chalk.white(" setup ")+chalk.gray("Settings / switch mode")),console.log(chalk.white(" lang [code] ")+chalk.gray("Switch language")),console.log(chalk.white(" clear ")+chalk.gray("Clear screen")),console.log(chalk.white(" exit ")+chalk.gray("Quit")),void console.log();if(!o)return console.log(chalk.bold.yellow(" Restricted Mode โ€” activate with a token to unlock all commands")),console.log(),console.log(chalk.white(" activate <token> ")+chalk.gray("Unlock full access")),console.log(chalk.white(" ref [topic] ")+chalk.gray("Quick reference")),console.log(chalk.white(" exit ")+chalk.gray("Quit")),void console.log();console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log(chalk.bold.white(" How it works")),console.log(),console.log(chalk.gray(" 1. Browse ")+chalk.white("challenges")+chalk.gray(" and pick one")),console.log(chalk.gray(" 2. ")+chalk.white("open <id>")+chalk.gray(" to read the challenge")),console.log(chalk.gray(" 3. Use ")+chalk.white("ai4ctf")+chalk.gray(" to chat with AI when stuck")),console.log(chalk.gray(" 4. ")+chalk.white("submit <id> <flag>")+chalk.gray(" to score points")),console.log(chalk.gray(" 5. Check ")+chalk.white("scoreboard")+chalk.gray(" to track your rank")),console.log(chalk.cyan(" โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•")),console.log();for(const o of["Competition","AI Teammate","Tools","System"]){console.log(chalk.bold.white(` ${o}`));for(const e of s(o))console.log(chalk.white(` ${e.label.padEnd(20)}`)+chalk.gray(e.text)),"System"===o&&"resume"===e.label&&console.log(chalk.white(" #<candidate> ")+chalk.gray("Stage a draft answer (never auto-submits)"));"Tools"===o&&console.log(chalk.white(" man <tool> ")+chalk.bold.yellow("โ˜… ")+chalk.gray("How to use a tool (steghide, nmapโ€ฆ); ")+chalk.cyan("man tools")+chalk.gray(" = list. Bare ")+chalk.cyan("man")+chalk.gray(" = this list.")),console.log()}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.535",
3
+ "version": "2.19.536",
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": {