icoa-cli 2.19.487 β 2.19.490
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib/access.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as t}from"node:crypto";import{execSync as e}from"node:child_process";import{platform as n}from"node:os";import{getConfig as r,saveConfig as i,getIcoaDir as o,getInstallSalt as
|
|
1
|
+
import{createHash as t}from"node:crypto";import{execSync as e}from"node:child_process";import{platform as n}from"node:os";import{getConfig as r,saveConfig as i,getIcoaDir as o,getInstallSalt as s}from"./config.js";import{readFileSync as a,existsSync as c}from"node:fs";import{join as u}from"node:path";import{deriveFileKey as d,readSignedFile as p,writeSignedFile as f,recordVerdict as m}from"./secure-store.js";const l=/^ICOA-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/;export function isFirstRunOrUpgrade(t){return r().lastVersion!==t}export function markVersionSeen(t){i({lastVersion:t})}const g=new Set(["ref","help","exit","quit","q","clear","cls","activate","doctor","aienv","ipynb","kaggle","tmux"]);export function isActivated(){return!!r().accessToken}export function getDeviceFingerprint(){const o=r();if(o.deviceFingerprint)return o.deviceFingerprint;const u=s(),d=function(){try{if("darwin"===n()){const t=e("ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID",{encoding:"utf-8"}).match(/"([A-F0-9-]+)"/);if(t)return t[1]}else if("linux"===n()){if(c("/etc/machine-id"))return a("/etc/machine-id","utf-8").trim()}else if("win32"===n())return e('powershell -Command "(Get-CimInstance Win32_ComputerSystemProduct).UUID"',{encoding:"utf-8"}).trim()}catch{}return""}(),p=t("sha256").update(`${d}|${u}`).digest("hex");try{i({deviceFingerprint:p})}catch{}return p}const x="token-bindings";export async function activateToken(e){if(!function(t){return l.test(t.trim().toUpperCase())}(e))return"invalid";const n=e.trim().toUpperCase(),r=getDeviceFingerprint(),a=u(o(),"token-bindings.json"),c=d(s(),x),{data:g,verdict:h}=p(a,c);m(x,h);const v=g||{},w=function(e){return t("sha256").update(e.trim().toUpperCase()).digest("hex")}(e),y=v[w];if(y&&y!==r)return"already_bound";try{const{httpFetch:t}=await import("./http.js"),{EXAM_SERVER:e}=await import("./exam-server.js"),i=await t(`${e}/api/icoa/env-activate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:n,fingerprint:r}),timeoutMs:1e4,idempotent:!0});if(!i.ok)return"network";const o=await i.json(),s=o?.data?.status;if("already_bound"===s)return"already_bound";if("ok"!==s)return"invalid"}catch{return"network"}return v[w]=r,f(a,v,c),i({accessToken:n,deviceFingerprint:r}),"ok"}export function isDeviceMatch(){const t=r();return!t.deviceFingerprint||t.deviceFingerprint===getDeviceFingerprint()}export function isFreeCommand(t){return g.has(t.toLowerCase())}const h=()=>u(o(),"session-state.json"),v="session-state";function w(){return d(s(),v)}function y(){return{startedAt:(new Date).toISOString(),lastExitAt:null,lastResumeAt:null,exitCount:0,totalAwaySeconds:0}}function A(){const{data:t,verdict:e}=p(h(),w());return m(v,e),t?{...y(),...t}:y()}function S(t){const e={...A(),...t};f(h(),e,w())}export function recordExit(){const t=A();t.lastExitAt=(new Date).toISOString(),t.exitCount++,S(t)}export function recordResume(){const t=A();if(!t.lastExitAt)return null;const e=new Date(t.lastExitAt).getTime(),n=Date.now(),r=Math.round((n-e)/1e3);return t.lastResumeAt=(new Date).toISOString(),t.totalAwaySeconds+=r,S(t),{awaySeconds:r,exitCount:t.exitCount}}
|
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{dispatchable as n,helpRows as l,shortcutFor as a,subcommandsOf as s,surface as r}from"./lib/commands.js";import{distance as i}from"fastest-levenshtein";import{isConnected as c,getConfig as g,saveConfig as y}from"./lib/config.js";import{ensureLangCache as m}from"./lib/translations-fetcher.js";import{loadUiPack as d}from"./lib/i18n.js";import{isActivated as p,activateToken as u,isFreeCommand as h,isDeviceMatch as w,recordExit as f,recordResume as b,isFirstRunOrUpgrade as x,markVersionSeen as v}from"./lib/access.js";import{setReplMode as k}from"./lib/ui.js";import{returnToMainMenu as C,printMenuHint as A,menuHintInline as I,registerRealExit as $}from"./lib/menu-nav.js";import{setMainRl as T}from"./lib/main-rl.js";import{shellSplit as E}from"./lib/shell-split.js";import{isChatActive as S,handleChatMessage as O}from"./commands/ai4ctf.js";import{renderToolMan as j}from"./lib/tool-man.js";import{isCtf4aiActive as N,handleCtf4aiMessage as L}from"./commands/ctf4ai-demo.js";import{isCtf4VlaActive as D,handleCtf4VlaMessage as P}from"./commands/ctf4vla.js";import{isDemo2Active as M}from"./commands/demo2.js";import{isSprintActive as q}from"./commands/sprint.js";import{isCardDeckActive as F}from"./lib/card-engine.js";import{hasAnySimHistory as R,lastArmAt as U,lastBundledAt as _,lastSimAt as B}from"./lib/sim-cooldown.js";import{getExamState as W,getRealExamState as Y,getDemoState as Q,practicalChatCommand as X}from"./lib/exam-state.js";import{resolveResumePoint as z}from"./lib/resume.js";import{buildStatusLine as Z}from"./lib/statusline.js";import{startBgTask as J,startAsyncTask as V,listBgTasks as H,getBgTask as G,drainCompleted as K,killAllBgTasks as oo,runningCount as eo}from"./lib/bgtasks.js";import{computeStart as to,renderStart as no}from"./commands/challenge.js";import{addDraft as lo,listDrafts as ao,removeDraft as so,clearDrafts as ro}from"./lib/drafts.js";import{resetTerminalTheme as io}from"./lib/theme.js";import{ensureSandbox as co,runInSandbox as go,isDockerAvailable as yo}from"./lib/sandbox.js";import{checkShellRisk as mo,logShellAudit as po,getActiveCwd as uo}from"./lib/exam-sandbox.js";import{logCommand as ho}from"./lib/logger.js";import{startLogSync as wo,stopLogSync as fo}from"./lib/log-sync.js";import{installInputDynamics as bo,uninstallInputDynamics as xo,stripTerminalMarkers as vo,rearmFocusMode as ko}from"./lib/input-dynamics.js";import{startBroadcastPoll as Co,stopBroadcastPoll as Ao,showBroadcast as Io,isCompetitionJoined as $o,isMelCompetition as To,isLeaderAccount as Eo,isLeaderSession as So,fetchPublicScoreboard as Oo,isCommsActive as jo}from"./lib/comms.js";import{enterMemoScreen as No,enterJuryScreen as Lo}from"./commands/comms.js";import{existsSync as Do,mkdirSync as Po,readFileSync as Mo,writeFileSync as qo}from"node:fs";import{join as Fo}from"node:path";import{homedir as Ro}from"node:os";const Uo="# 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",_o=Date.now();function Bo(){return To()?chalk.yellow("icoa 2026> "):Y()?chalk.cyan("icoa exam> "):function(){const o=Q();return!(!o||"demo-free"!==o.session?.examId)&&new Date(o.session.startedAt||0).getTime()>=_o}()?chalk.yellow("icoa demo> "):chalk.green("icoa> ")}const Wo=Fo(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"]),Qo="__REPL_NO_EXIT__",Xo="2.5.1",zo=r();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=i(t,o);e<n.dist&&(n={word:o,dist:e})}return n.dist>0&&n.dist<=e?n.word:null}const Zo=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=s(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(Qo)};try{await o.parseAsync(["node","icoa",...e.command])}catch(o){if(!(o instanceof Error&&o.message===Qo))throw o}finally{process.exit=t}return e}function Ho(){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,l){process.env.ICOA_INSIDE_REPL="1";let a=!1;if(To()){const o=g().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)||(y({ctfdUrl:"",token:"",sessionCookie:"",userId:null,userName:"",teamId:null,country:"",joinedAt:""}),a=!0)}const s=g(),r=c(),i=process.exit.bind(process);$(i);const E=p();if(s.language&&"en"!==s.language&&(await m(s.language,{silent:!0}),d(s.language)),s.demoCleanedForVersion!==Xo){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{}y({demoCleanedForVersion:Xo})}const{select:Q,confirm:ko}=await import("@inquirer/prompts"),_o=s.mode||"",oe=""===_o?"instant":["instant","learn","selection","olympiad"].includes(_o)?_o:"selection",ee=[{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("free demo or 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"}];""===_o&&(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 te="";for(;!te;){let o;const e=process.env.ICOA_TEST_BOOT_MODE;if(e&&["instant","learn","selection","olympiad"].includes(e))o=e;else try{o=await Q({message:"Mode",choices:ee,default:oe||"instant"})}catch(o){throw o instanceof Error&&"ExitPromptError"===o.name&&(console.log(),console.log(chalk.gray(" Goodbye.")),process.exit(0)),o}if("about"!==o)te=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"===te&&"olympiad"!==oe){console.log(),console.log(chalk.yellow(" This mode will download ~500MB of CTF tools and AI models."));let o=!0;try{o=await ko({message:"Continue?",default:!0})}catch(e){if(!(e instanceof Error&&"ExitPromptError"===e.name))throw e;o=!1}o||(te="selection",console.log(chalk.gray(" Switched to National Selection mode.")))}if(te!==oe&&y({mode:te}),console.log(),"olympiad"===te&&x(Xo)){v(Xo),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(l){const o=b();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"===te)console.log(chalk.gray(" βββ exam hall Β· 90 min per paper once started Β· no pause βββ")),console.log(),Ho();else if("embodied"===te)!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=_()>0||B()>0,e=U()>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"===te)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(),y({mode:"selection"}),te="selection";else{if("learn"===te){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,n=o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o)?`${o.slice(0,2)}β’β’β’β’β’β’${o.slice(-2)}`:o,l=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 a=e?t:t.slice(0,o.listMax),s=o=>Math.max(...a.map(e=>o(e).length)),r=s(o=>o.curriculumId),i=s(o=>`card ${o.currentCard}/${o.totalCards}`),c=s(o=>l(o.lastSeenAt));return a.forEach((o,e)=>{const t=o.token===o.curriculumId?"":` ${n(o.token)}`;console.log(chalk.green(` ${e+1} `)+chalk.bold.white(o.curriculumId.padEnd(r))+chalk.gray(` ${`card ${o.currentCard}/${o.totalCards}`.padEnd(i)} ${l(o.lastSeenAt).padEnd(c)}${t}`))}),a.length};if(1===t.length){const o=t[0],e=l(o.lastSeenAt);console.log(chalk.green(" βΈ Continue ")+chalk.bold.white(o.curriculumId)+chalk.gray(` Β· card ${o.currentCard}/${o.totalCards}${e?` Β· ${e}`:""} Β· ${n(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()}console.log(chalk.gray(" Three tracks Β· same difficulty curve.")),console.log(),console.log(chalk.white(" Free 12-card demos β paste the full command:")),console.log(),console.log(chalk.gray(" π€ ai4ctf AI as your teammate ")+chalk.bold.yellow("learn AI4CTFDEMO01")),console.log(chalk.gray(" π ctf4ai AI as your target ")+chalk.bold.yellow("learn CTF4AIDEMO01")),console.log(chalk.gray(" π€ ctf4eai Embodied AI Security ")+chalk.bold.yellow("learn LEARNDEMO01")),console.log(),console.log(chalk.gray(" Got a cohort token? Type ")+chalk.bold.yellow("learn <TOKEN>")+chalk.gray(" (e.g. ")+chalk.bold.yellow("learn EAABCD1234")+chalk.gray(").")),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(),y({mode:"selection"}),void C()}if(["pandahelpme31","/pandahelpme31","panda help me 31","pandahelpme"].includes(c)){const{runSprint:o}=await import("./commands/sprint.js");return await o(),y({mode:"selection"}),void C()}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),y({mode:"selection"}),void C()}if("ioailab"===c||"/ioailab"===c){const{runIoailabStandalone:o}=await import("./commands/ioailab.js");return await o(),await l(),y({mode:"selection"}),void C()}let g=n(i);if("back"===g.kind)break;if("continue"===g.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(" Start with a free demo above, or paste your cohort token.")),console.log(),r===s){await l();break}continue}const{which:o}=g;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]}g={kind:"token",token:e.token}}if("ambiguous"===g.kind||"unknown"===g.kind){if(console.log(),console.log(chalk.yellow(` ${g.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; the free demos need no token.")),console.log(),await l();break}continue}if(g.from){const{loadCurriculumById:o}=await import("./lib/learn-curricula.js");if(!await o(g.token,g.token)){if(console.log(),console.log(chalk.yellow(` No free demo for "${g.from}".`)),console.log(chalk.gray(" Free demos exist for most tracks β try ")+chalk.bold.green("ai4ctf")+chalk.gray(", ")+chalk.bold.green("biology")+chalk.gray(", ")+chalk.bold.green("ioipy")+chalk.gray(". With a cohort token, paste the token itself.")),console.log(),r===s){await l();break}continue}}if(!/^[A-Z0-9]+DEMO01$/i.test(g.token)&&/^[A-Z]{2}[A-Z0-9]{8}$/i.test(g.token)){console.log(),console.log(chalk.gray(" Checking tokenβ¦"));const{validateEAToken:o}=await import("./lib/learn-curricula.js"),e=await o(g.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(`: ${g.token}`)),console.log(),y({mode:"selection"}),process.env.ICOA_LEARN_EMBEDDED="1";const{setLearnSessionStarted:m}=await import("./lib/learn-outcome.js");m(!1);try{await e.parseAsync(["node","icoa","learn",g.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{}return y({mode:"selection"}),void C()}"organizer"===te?(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(),r?(console.log(chalk.green(` Logged in as ${s.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()):r?(console.log(chalk.green.bold(` Welcome back, ${s.userName}!`)),console.log(chalk.gray(` Connected to ${s.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?(Do(Wo)||Po(Wo,{recursive:!0}),console.log(chalk.green.bold(" Welcome, competitor!")),console.log(chalk.gray(` Workspace: ${Wo}`)),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 ne=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)ne(e)};ne(e);const le=o({input:process.stdin,output:process.stdout,prompt:Bo(),terminal:!0,completer:Jo});T(le),bo(!1!==g().bracketedPaste);let ae=!1;if(k(!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()),To()){const o=g().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=>{le.question(chalk.white(" > "),e=>o(e.trim()))})).toLowerCase()&&(y({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()}$o()&&Co(()=>le.prompt());let se=null;const re=le.prompt.bind(le);le.prompt=o=>{if(!(S()||N()||D()||M()||F()||jo()||q()||(le.setPrompt(Bo()),o)))try{for(const o of K()){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=Z();o&&o!==se?(console.log(o),se=o):o||(se=null)}catch{}re(o)};const ie=z();ie&&(console.log(chalk.cyan(" β» Continue where you left off: ")+chalk.white(ie.label)+(ie.urgent?chalk.yellow(" (exam timer running)"):"")),console.log(chalk.gray(" type ")+chalk.cyan("resume")+chalk.gray(" to jump back in.")),console.log()),le.prompt(),le.on("line",async o=>{if(ae)return;let l=vo(o.trim());if(!l)return le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),void le.prompt();if(/^icoa\s+\S/i.test(l)&&(l=l.replace(/^icoa\s+/i,"")),l.startsWith("/")&&!l.startsWith("//")){const o=l.slice(1).split(/\s+/)[0].toLowerCase(),t=l.slice(1+o.length).trim();if("ai"===o)return ae=!0,await async function(o,e){if(S())return void(o?await O(o):console.log(chalk.gray(" You are already in the AI chat β just type your message.")));if(N())return void(o?await L(o):console.log(chalk.gray(" You are already in the CTF4AI target chat β just type your message.")));if(D())return void(o?await P(o):console.log(chalk.gray(" You are already in the Embodied-AI chat β just type your message.")));ho(o?`/ai ${o}`:"/ai");const t=process.exit;process.exit=()=>{throw new Error(Qo)};try{await e.parseAsync(["node","icoa","ai4ctf"])}catch(o){if(!(o instanceof Error&&o.message===Qo))throw o}finally{process.exit=t}o&&S()&&await O(o)}(t,e),ae=!1,le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),void le.prompt();!(S()||N()||D()||M()||F()||jo())&&zo.includes(o)&&(l=l.slice(1))}if("resume"===l.toLowerCase()){const o=z();return o?(ho(`resume β ${o.command.join(" ")}`),ae=!0,await Vo(e),ae=!1,le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),void le.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 le.prompt())}const a=S()||N()||D()||M()||F();if(!a&&("bg"===l.toLowerCase()||/^bg\s/i.test(l))){const o=l.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 le.prompt();const e=uo(),t=mo(o);po({cwd:e,input:`bg ${o}`,riskFlags:t}),t.length>0&&Y()&&console.log(chalk.yellow(` β Action flagged: ${t.join(", ")} β logged.`));const n=J(o,e);return console.log(),console.log(chalk.cyan(` βΈ background task #${n.id} started`)+chalk.gray(` (${eo()} running)`)),console.log(chalk.gray(" ")+chalk.white(o)),console.log(chalk.gray(" view: ")+chalk.cyan("tasks")+chalk.gray(" Β· output: ")+chalk.cyan(`tasks ${n.id}`)),console.log(),void le.prompt()}if(!a&&("tasks"===l.toLowerCase()||/^tasks\s/i.test(l))){const o=l.replace(/^tasks\s*/i,"").trim(),e=H();if(console.log(),o){const e=G(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 le.prompt()}if(!a&&/&\s*$/.test(l)&&/^challenge\s+start\s+/i.test(l)){const o=l.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 le.prompt();if(!c())return console.log(),console.log(chalk.red(" Not connected. ")+chalk.gray("Run ")+chalk.cyan("join <url>")+chalk.gray(" first.")),console.log(),void le.prompt();ho(`challenge start ${t}${e?" --new":""} & (background)`);const n=V(`challenge start ${t}`,()=>to(t,e),o=>no(t,o));return console.log(),console.log(chalk.cyan(` βΈ background task #${n.id}: `)+chalk.white(`starting ${t}`)+chalk.gray(" β you can keep working; the connection info appears here when it is ready.")),console.log(),void le.prompt()}if(!a&&l.startsWith("#")){const o=l.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 le.prompt();const e=W(),t=e?.session?.examId??null,n=e?e._lastQ||1:null,a=lo(o,t,n);return ho(`draft #${a.id} (not submitted)`),console.log(),console.log(chalk.green(` β draft #${a.id} saved`)+(n?chalk.gray(` (Q${n})`):"")+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 le.prompt()}if(!a&&("drafts"===l.toLowerCase()||/^drafts\s/i.test(l))){const o=l.replace(/^drafts\s*/i,"").trim().toLowerCase();if("clear"===o){const o=ro();return console.log(),console.log(chalk.gray(` Cleared ${o} draft${1===o?"":"s"}.`)),console.log(),void le.prompt()}const e=o.match(/^(?:rm|remove|del|delete)\s+(\d+)$/);if(e){const o=so(Number(e[1]));return console.log(),console.log(o?chalk.gray(` Removed draft #${e[1]}.`):chalk.yellow(` No draft #${e[1]}.`)),console.log(),void le.prompt()}const t=W(),n=ao(t?.session?.examId??null);if(console.log(),0===n.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 n){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 le.prompt()}if("menu"===l||"menu confirm"===l)return Y()&&"menu confirm"!==l?(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 le.prompt()):void C(le);if(S()){ae=!0;const o=await O(l);return ae=!1,"exit"===o&&le.setPrompt(Bo()),void le.prompt()}if(N()){ae=!0;const o=await L(l);return ae=!1,"exit"!==o&&"solved"!==o||le.setPrompt(Bo()),void le.prompt()}if(D()){ae=!0;const o=await P(l);return ae=!1,"exit"===o&&le.setPrompt(Bo()),le.setPrompt(D()?chalk.bold.cyan("icoa ctf4eai> "):Bo()),void le.prompt()}if(ho(l),"exit"===l)return W()?(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 le.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"===te&&Ho(),void le.prompt());if("quit"===l||"q"===l||"quit confirm"===l){const o=W();return o&&"demo-free"!==o.session.examId&&"quit confirm"!==l?(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 le.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)."))),fo(),xo(),Ao(),oo(),f(),console.log(chalk.gray(" Session saved. Use ")+chalk.white("icoa --resume")+chalk.gray(" to continue.")),io(),void i(0))}if("back"===l){const o=W(),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=g();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"===te?Ho():console.log(chalk.gray(" Already at main menu."))}return void le.prompt()}if("help"===l||"?"===l){if(W()){ae=!0;try{await e.parseAsync(["node","icoa","exam","help"])}catch{}return ae=!1,void le.prompt()}return Ko(p(),te),void le.prompt()}if("man"===l||"manual"===l)return Ko(p(),te),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 le.prompt();if(/^(?:man|manual)\s+\S/i.test(l))return j(l.replace(/^(?:man|manual)\s+/i,"")),void le.prompt();if("more help"===l.toLowerCase()&&W()){ae=!0;try{await e.parseAsync(["node","icoa","exam","more-help"])}catch{}return ae=!1,void le.prompt()}if("continue"===l.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 le.prompt();if(/^ICOA-[A-Z]{2,3}-\d{1,6}$/i.test(l.trim())){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",l.trim()])}catch{}return ae=!1,void le.prompt()}if(/^[A-Z]{2}[0-9A-HJKMNP-TV-Z]{8}$/i.test(l.trim())){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",l.trim().toUpperCase()])}catch{}return ae=!1,void le.prompt()}const s=l.match(/^exam\s+([A-Z]{2}[0-9A-HJKMNP-TV-Z]{8})$/i);if(s){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",s[1].toUpperCase()])}catch{}return ae=!1,void le.prompt()}const r=l.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 le.prompt()}const y=l.match(/^exam\s+(\S+)$/i);if(y&&!Zo.has(y[1].toLowerCase())){const o=y[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 le.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 le.prompt()}if("clear"===l||"cls"===l)return console.clear(),void le.prompt();if("news"===l)return $o()?Io():console.log(chalk.gray(" No competition joined. Use ")+chalk.white("join <url>")+chalk.gray(".")),void le.prompt();if("memo"===l){if(!$o())return console.log(chalk.gray(" Join a competition first: ")+chalk.white("join <url>")),void le.prompt();ae=!0;try{await No()}catch{}return void(ae=!1)}const m=So()||Eo(g().userName||"");if("jury"===l&&m){ae=!0;try{await Lo()}catch{}return void(ae=!1)}if(m&&So()&&"scoreboard"===l.split(/\s+/)[0]){ae=!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 ae=!1,void le.prompt()}if(m&&To()){const o=l.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 le.prompt()}if(l.startsWith("activate ")){const o=l.slice(9).trim(),e=u(o);return"ok"===e?console.log(chalk.green(" Access granted! Token bound to this device.")):"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 le.prompt()}if("activate"===l)return console.log(chalk.gray(" Usage: ")+chalk.white("activate <token>")),console.log(),void le.prompt();const d=W();if(d){const o=l.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)},n=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=X(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 l=d._lastQ||1;if(t(l))return a(l),void le.prompt();if(n(l))return console.log(),console.log(chalk.yellow(` Q${l} 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 ${l} 42`)+chalk.gray(")")),console.log(),void le.prompt();ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(l),o])}catch{}return ae=!1,void le.prompt()}if(/^-?\d+$/.test(o)){const t=d._lastQ||1;if(n(t)){ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(t),o])}catch{}return ae=!1,void le.prompt()}}const s=o.match(/^(\d+)\s+([ABCDE]|-?\d+)$/);if(s){const o=parseInt(s[1],10);if(t(o))return a(o),void le.prompt();ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",s[1],s[2]])}catch{}return ae=!1,void le.prompt()}}const b=l.split(/\s+/)[0].toLowerCase(),x=/^python3?(\.\d+)?$/.test(b),v="ls"===b||"pwd"===b||"tmux"===b,k=l.startsWith("!")||b.startsWith("!")||x||v,A=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"]),I=()=>{console.log(chalk.gray(" Shell commands need ")+chalk.bold.cyan("!")+chalk.gray(" prefix. Try: ")+chalk.bold.cyan(`!${l}`)),console.log()};if("py"===b||"pylist"===b)return console.log(chalk.yellow(` ${b} 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"===b?"/py":"/pylist")+chalk.gray(" on any card.")),console.log(),void le.prompt();if("embodied"===te&&!k&&!["doctor","demo2","learn","exam","ctf4eai","ctf4vla","eai","arena","lang","ref","setup","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(b))return A.has(b)?(I(),void le.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 le.prompt());if("selection"===te&&!k&&!["doctor","exam","demo","demo2","demo4","demo5","retry","nations","next","prev","continue","setup","lang","ref","ai4ctf","ctf4ai","mark","unmark","review","submit","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(b)){if(A.has(b))return I(),void le.prompt();if(n().includes(b))console.log(chalk.gray(` ${b} isn't available on this screen.`));else{console.log(chalk.yellow(` Unknown command: ${b}`));const o=nearestCommand(b);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 le.prompt()}if("organizer"===te&&!["doctor","join","exam","demo","retry","next","prev","logout","setup","lang","ref","ctf","mark","unmark","review","submit","tmux"].includes(b))return console.log(chalk.gray(" Not available in Organizer mode. Switch via: setup")),console.log(),void le.prompt();if(!("olympiad"!==te||p()&&w()||h(b)))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 le.prompt();if(!n().includes(b)){if("tmux"===b)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 le.prompt()}if(Yo.has(b))return console.log(chalk.yellow(` "${b}" 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(`!${l}`)),console.log(),void le.prompt();if(/(?:^|\s)(?:\/(?!home\/|Users\/|tmp\/)|\.\.\/|~\/)/.test(l)&&!l.startsWith("cd ")){const o=/(?:^|\s)\/(?!home\/\w+\/icoa-workspace|Users\/\w+\/icoa-workspace|tmp\/)/.test(l),e=/\.\./.test(l);if(o||e)return console.log(chalk.red(" Blocked: access outside workspace is not allowed.")),console.log(chalk.gray(` Workspace: ${Wo}`)),console.log(),void le.prompt()}let o=l.startsWith("!")?l.slice(1).trim():l;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=uo(),n=mo(l);po({cwd:e,input:l,riskFlags:n}),n.length>0&&Y()&&(console.log(chalk.yellow(` β Action flagged: ${n.join(", ")} β logged.`)),console.log()),/^(\S*python3?(\.\d+)?)\s*$/.test(o)&&(o=`PYTHONSTARTUP="${function(){const o=Fo(Ro(),".icoa");Do(o)||Po(o,{recursive:!0});const e=Fo(o,"python-startup.py");let t="";if(Do(e))try{t=Mo(e,"utf-8")}catch{}return t!==Uo&&qo(e,Uo),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 yo()&&await co()?await go(o,le):await Go(o,le,e)}catch{console.log(chalk.yellow(` Command failed: ${b}`))}return ae=!1,console.log(),void le.prompt()}ae=!0;const $=l.trim(),T=$.toLowerCase();let E,q=null,R="";if(d)if("submit"===T)q="final";else if(T.startsWith("submit ")){let o=$.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)?(q="flag",R=o):o&&/^[ABCDE]$/i.test(o)&&(q="flag",R=o.toUpperCase())}else/^ICOA\{[^}]+\}$/i.test($)&&(q="flag",R=$);E="final"===q?["exam","submit"]:"flag"===q?["exam","answer",String(d?._lastQ||1),R]:mapCommand(l);const U="ctf"===E[0]&&"join"===E[1];U&&le.pause(),process.exit=()=>{throw new Error(Qo)};try{await e.parseAsync(["node","icoa",...E])}catch(o){const e=o instanceof Error?o.message:String(o);if(e===Qo);else if(e.includes("commander.unknownCommand")){const o=nearestCommand(b.split(/\s+/)[0]||b);console.log(chalk.yellow(` Unknown command: ${b}.`)),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"===b||"flag"===b?(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: ${b}`)),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=i,ae=!1,U&&le.resume()}S()?le.setPrompt(chalk.magenta("icoa ai4ctf> ")):N()?le.setPrompt(chalk.red("icoa ctf4ai> ")):D()&&le.setPrompt(chalk.bold.cyan("icoa ctf4eai> ")),console.log(),le.prompt()}),le.on("SIGINT",()=>{if(console.log(),S()||N())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(W()){const o="demo-free"!==W().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(),le.prompt()}),le.on("close",()=>{fo(),xo(),Ao(),oo(),f(),io(),i(0)}),"1"===process.env.ICOA_AUTO_RESUME&&(delete process.env.ICOA_AUTO_RESUME,z()&&(ae=!0,await Vo(e),ae=!1,le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),le.prompt()))}function Go(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{}ko(),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 Ko(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 l(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{dispatchable as n,helpRows as l,shortcutFor as a,subcommandsOf as s,surface as r}from"./lib/commands.js";import{distance as i}from"fastest-levenshtein";import{isConnected as c,getConfig as g,saveConfig as y}from"./lib/config.js";import{ensureLangCache as m}from"./lib/translations-fetcher.js";import{loadUiPack as d}from"./lib/i18n.js";import{isActivated as p,activateToken as u,isFreeCommand as h,isDeviceMatch as w,recordExit as f,recordResume as b,isFirstRunOrUpgrade as x,markVersionSeen as v}from"./lib/access.js";import{setReplMode as k}from"./lib/ui.js";import{returnToMainMenu as C,printMenuHint as A,menuHintInline as I,registerRealExit as $}from"./lib/menu-nav.js";import{setMainRl as T}from"./lib/main-rl.js";import{shellSplit as E}from"./lib/shell-split.js";import{isChatActive as S,handleChatMessage as O}from"./commands/ai4ctf.js";import{renderToolMan as j}from"./lib/tool-man.js";import{isCtf4aiActive as N,handleCtf4aiMessage as L}from"./commands/ctf4ai-demo.js";import{isCtf4VlaActive as D,handleCtf4VlaMessage as P}from"./commands/ctf4vla.js";import{isDemo2Active as M}from"./commands/demo2.js";import{isSprintActive as q}from"./commands/sprint.js";import{isCardDeckActive as F}from"./lib/card-engine.js";import{hasAnySimHistory as R,lastArmAt as U,lastBundledAt as _,lastSimAt as B}from"./lib/sim-cooldown.js";import{getExamState as W,getRealExamState as Y,getDemoState as Q,practicalChatCommand as X}from"./lib/exam-state.js";import{resolveResumePoint as z}from"./lib/resume.js";import{buildStatusLine as Z}from"./lib/statusline.js";import{startBgTask as J,startAsyncTask as V,listBgTasks as H,getBgTask as G,drainCompleted as K,killAllBgTasks as oo,runningCount as eo}from"./lib/bgtasks.js";import{computeStart as to,renderStart as no}from"./commands/challenge.js";import{addDraft as lo,listDrafts as ao,removeDraft as so,clearDrafts as ro}from"./lib/drafts.js";import{resetTerminalTheme as io}from"./lib/theme.js";import{ensureSandbox as co,runInSandbox as go,isDockerAvailable as yo}from"./lib/sandbox.js";import{checkShellRisk as mo,logShellAudit as po,getActiveCwd as uo}from"./lib/exam-sandbox.js";import{logCommand as ho}from"./lib/logger.js";import{startLogSync as wo,stopLogSync as fo}from"./lib/log-sync.js";import{installInputDynamics as bo,uninstallInputDynamics as xo,stripTerminalMarkers as vo,rearmFocusMode as ko}from"./lib/input-dynamics.js";import{startBroadcastPoll as Co,stopBroadcastPoll as Ao,showBroadcast as Io,isCompetitionJoined as $o,isMelCompetition as To,isLeaderAccount as Eo,isLeaderSession as So,fetchPublicScoreboard as Oo,isCommsActive as jo}from"./lib/comms.js";import{enterMemoScreen as No,enterJuryScreen as Lo}from"./commands/comms.js";import{existsSync as Do,mkdirSync as Po,readFileSync as Mo,writeFileSync as qo}from"node:fs";import{join as Fo}from"node:path";import{homedir as Ro}from"node:os";const Uo="# 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",_o=Date.now();function Bo(){return To()?chalk.yellow("icoa 2026> "):Y()?chalk.cyan("icoa exam> "):function(){const o=Q();return!(!o||"demo-free"!==o.session?.examId)&&new Date(o.session.startedAt||0).getTime()>=_o}()?chalk.yellow("icoa demo> "):chalk.green("icoa> ")}const Wo=Fo(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"]),Qo="__REPL_NO_EXIT__",Xo="2.5.1",zo=r();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=i(t,o);e<n.dist&&(n={word:o,dist:e})}return n.dist>0&&n.dist<=e?n.word:null}const Zo=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=s(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(Qo)};try{await o.parseAsync(["node","icoa",...e.command])}catch(o){if(!(o instanceof Error&&o.message===Qo))throw o}finally{process.exit=t}return e}function Ho(){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,l){process.env.ICOA_INSIDE_REPL="1";let a=!1;if(To()){const o=g().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)||(y({ctfdUrl:"",token:"",sessionCookie:"",userId:null,userName:"",teamId:null,country:"",joinedAt:""}),a=!0)}const s=g(),r=c(),i=process.exit.bind(process);$(i);const E=p();if(s.language&&"en"!==s.language&&(await m(s.language,{silent:!0}),d(s.language)),s.demoCleanedForVersion!==Xo){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{}y({demoCleanedForVersion:Xo})}const{select:Q,confirm:ko}=await import("@inquirer/prompts"),_o=s.mode||"",oe=""===_o?"instant":["instant","learn","selection","olympiad"].includes(_o)?_o:"selection",ee=[{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("free demo or 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"}];""===_o&&(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 te="";for(;!te;){let o;const e=process.env.ICOA_TEST_BOOT_MODE;if(e&&["instant","learn","selection","olympiad"].includes(e))o=e;else try{o=await Q({message:"Mode",choices:ee,default:oe||"instant"})}catch(o){throw o instanceof Error&&"ExitPromptError"===o.name&&(console.log(),console.log(chalk.gray(" Goodbye.")),process.exit(0)),o}if("about"!==o)te=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"===te&&"olympiad"!==oe){console.log(),console.log(chalk.yellow(" This mode will download ~500MB of CTF tools and AI models."));let o=!0;try{o=await ko({message:"Continue?",default:!0})}catch(e){if(!(e instanceof Error&&"ExitPromptError"===e.name))throw e;o=!1}o||(te="selection",console.log(chalk.gray(" Switched to National Selection mode.")))}if(te!==oe&&y({mode:te}),console.log(),"olympiad"===te&&x(Xo)){v(Xo),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(l){const o=b();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"===te)console.log(chalk.gray(" βββ exam hall Β· 90 min per paper once started Β· no pause βββ")),console.log(),Ho();else if("embodied"===te)!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=_()>0||B()>0,e=U()>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"===te)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(),y({mode:"selection"}),te="selection";else{if("learn"===te){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,n=o=>/^[A-Z]{2}[A-Z0-9]{8}$/i.test(o)?`${o.slice(0,2)}β’β’β’β’β’β’${o.slice(-2)}`:o,l=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 a=e?t:t.slice(0,o.listMax),s=o=>Math.max(...a.map(e=>o(e).length)),r=s(o=>o.curriculumId),i=s(o=>`card ${o.currentCard}/${o.totalCards}`),c=s(o=>l(o.lastSeenAt));return a.forEach((o,e)=>{const t=o.token===o.curriculumId?"":` ${n(o.token)}`;console.log(chalk.green(` ${e+1} `)+chalk.bold.white(o.curriculumId.padEnd(r))+chalk.gray(` ${`card ${o.currentCard}/${o.totalCards}`.padEnd(i)} ${l(o.lastSeenAt).padEnd(c)}${t}`))}),a.length};if(1===t.length){const o=t[0],e=l(o.lastSeenAt);console.log(chalk.green(" βΈ Continue ")+chalk.bold.white(o.curriculumId)+chalk.gray(` Β· card ${o.currentCard}/${o.totalCards}${e?` Β· ${e}`:""} Β· ${n(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()}console.log(chalk.gray(" Three tracks Β· same difficulty curve.")),console.log(),console.log(chalk.white(" Free 12-card demos β paste the full command:")),console.log(),console.log(chalk.gray(" π€ ai4ctf AI as your teammate ")+chalk.bold.yellow("learn AI4CTFDEMO01")),console.log(chalk.gray(" π ctf4ai AI as your target ")+chalk.bold.yellow("learn CTF4AIDEMO01")),console.log(chalk.gray(" π€ ctf4eai Embodied AI Security ")+chalk.bold.yellow("learn LEARNDEMO01")),console.log(),console.log(chalk.gray(" Got a cohort token? Type ")+chalk.bold.yellow("learn <TOKEN>")+chalk.gray(" (e.g. ")+chalk.bold.yellow("learn EAABCD1234")+chalk.gray(").")),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(),y({mode:"selection"}),void C()}if(["pandahelpme31","/pandahelpme31","panda help me 31","pandahelpme"].includes(c)){const{runSprint:o}=await import("./commands/sprint.js");return await o(),y({mode:"selection"}),void C()}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),y({mode:"selection"}),void C()}if("ioailab"===c||"/ioailab"===c){const{runIoailabStandalone:o}=await import("./commands/ioailab.js");return await o(),await l(),y({mode:"selection"}),void C()}let g=n(i);if("back"===g.kind)break;if("continue"===g.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(" Start with a free demo above, or paste your cohort token.")),console.log(),r===s){await l();break}continue}const{which:o}=g;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]}g={kind:"token",token:e.token}}if("ambiguous"===g.kind||"unknown"===g.kind){if(console.log(),console.log(chalk.yellow(` ${g.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; the free demos need no token.")),console.log(),await l();break}continue}if(g.from){const{loadCurriculumById:o}=await import("./lib/learn-curricula.js");if(!await o(g.token,g.token)){if(console.log(),console.log(chalk.yellow(` No free demo for "${g.from}".`)),console.log(chalk.gray(" Free demos exist for most tracks β try ")+chalk.bold.green("ai4ctf")+chalk.gray(", ")+chalk.bold.green("biology")+chalk.gray(", ")+chalk.bold.green("ioipy")+chalk.gray(". With a cohort token, paste the token itself.")),console.log(),r===s){await l();break}continue}}if(!/^[A-Z0-9]+DEMO01$/i.test(g.token)&&/^[A-Z]{2}[A-Z0-9]{8}$/i.test(g.token)){console.log(),console.log(chalk.gray(" Checking tokenβ¦"));const{validateEAToken:o}=await import("./lib/learn-curricula.js"),e=await o(g.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(`: ${g.token}`)),console.log(),y({mode:"selection"}),process.env.ICOA_LEARN_EMBEDDED="1";const{setLearnSessionStarted:m}=await import("./lib/learn-outcome.js");m(!1);try{await e.parseAsync(["node","icoa","learn",g.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{}return y({mode:"selection"}),void C()}"organizer"===te?(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(),r?(console.log(chalk.green(` Logged in as ${s.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()):r?(console.log(chalk.green.bold(` Welcome back, ${s.userName}!`)),console.log(chalk.gray(` Connected to ${s.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?(Do(Wo)||Po(Wo,{recursive:!0}),console.log(chalk.green.bold(" Welcome, competitor!")),console.log(chalk.gray(` Workspace: ${Wo}`)),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 ne=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)ne(e)};ne(e);const le=o({input:process.stdin,output:process.stdout,prompt:Bo(),terminal:!0,completer:Jo});T(le),bo(!1!==g().bracketedPaste);let ae=!1;if(k(!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()),To()){const o=g().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=>{le.question(chalk.white(" > "),e=>o(e.trim()))})).toLowerCase()&&(y({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()}$o()&&Co(()=>le.prompt());let se=null;const re=le.prompt.bind(le);le.prompt=o=>{if(!(S()||N()||D()||M()||F()||jo()||q()||(le.setPrompt(Bo()),o)))try{for(const o of K()){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=Z();o&&o!==se?(console.log(o),se=o):o||(se=null)}catch{}re(o)};const ie=z();ie&&(console.log(chalk.cyan(" β» Continue where you left off: ")+chalk.white(ie.label)+(ie.urgent?chalk.yellow(" (exam timer running)"):"")),console.log(chalk.gray(" type ")+chalk.cyan("resume")+chalk.gray(" to jump back in.")),console.log()),le.prompt(),le.on("line",async o=>{if(ae)return;let l=vo(o.trim());if(!l)return le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),void le.prompt();if(/^icoa\s+\S/i.test(l)&&(l=l.replace(/^icoa\s+/i,"")),l.startsWith("/")&&!l.startsWith("//")){const o=l.slice(1).split(/\s+/)[0].toLowerCase(),t=l.slice(1+o.length).trim();if("ai"===o)return ae=!0,await async function(o,e){if(S())return void(o?await O(o):console.log(chalk.gray(" You are already in the AI chat β just type your message.")));if(N())return void(o?await L(o):console.log(chalk.gray(" You are already in the CTF4AI target chat β just type your message.")));if(D())return void(o?await P(o):console.log(chalk.gray(" You are already in the Embodied-AI chat β just type your message.")));ho(o?`/ai ${o}`:"/ai");const t=process.exit;process.exit=()=>{throw new Error(Qo)};try{await e.parseAsync(["node","icoa","ai4ctf"])}catch(o){if(!(o instanceof Error&&o.message===Qo))throw o}finally{process.exit=t}o&&S()&&await O(o)}(t,e),ae=!1,le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),void le.prompt();!(S()||N()||D()||M()||F()||jo())&&zo.includes(o)&&(l=l.slice(1))}if("resume"===l.toLowerCase()){const o=z();return o?(ho(`resume β ${o.command.join(" ")}`),ae=!0,await Vo(e),ae=!1,le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),void le.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 le.prompt())}const a=S()||N()||D()||M()||F();if(!a&&("bg"===l.toLowerCase()||/^bg\s/i.test(l))){const o=l.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 le.prompt();const e=uo(),t=mo(o);po({cwd:e,input:`bg ${o}`,riskFlags:t}),t.length>0&&Y()&&console.log(chalk.yellow(` β Action flagged: ${t.join(", ")} β logged.`));const n=J(o,e);return console.log(),console.log(chalk.cyan(` βΈ background task #${n.id} started`)+chalk.gray(` (${eo()} running)`)),console.log(chalk.gray(" ")+chalk.white(o)),console.log(chalk.gray(" view: ")+chalk.cyan("tasks")+chalk.gray(" Β· output: ")+chalk.cyan(`tasks ${n.id}`)),console.log(),void le.prompt()}if(!a&&("tasks"===l.toLowerCase()||/^tasks\s/i.test(l))){const o=l.replace(/^tasks\s*/i,"").trim(),e=H();if(console.log(),o){const e=G(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 le.prompt()}if(!a&&/&\s*$/.test(l)&&/^challenge\s+start\s+/i.test(l)){const o=l.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 le.prompt();if(!c())return console.log(),console.log(chalk.red(" Not connected. ")+chalk.gray("Run ")+chalk.cyan("join <url>")+chalk.gray(" first.")),console.log(),void le.prompt();ho(`challenge start ${t}${e?" --new":""} & (background)`);const n=V(`challenge start ${t}`,()=>to(t,e),o=>no(t,o));return console.log(),console.log(chalk.cyan(` βΈ background task #${n.id}: `)+chalk.white(`starting ${t}`)+chalk.gray(" β you can keep working; the connection info appears here when it is ready.")),console.log(),void le.prompt()}if(!a&&l.startsWith("#")){const o=l.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 le.prompt();const e=W(),t=e?.session?.examId??null,n=e?e._lastQ||1:null,a=lo(o,t,n);return ho(`draft #${a.id} (not submitted)`),console.log(),console.log(chalk.green(` β draft #${a.id} saved`)+(n?chalk.gray(` (Q${n})`):"")+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 le.prompt()}if(!a&&("drafts"===l.toLowerCase()||/^drafts\s/i.test(l))){const o=l.replace(/^drafts\s*/i,"").trim().toLowerCase();if("clear"===o){const o=ro();return console.log(),console.log(chalk.gray(` Cleared ${o} draft${1===o?"":"s"}.`)),console.log(),void le.prompt()}const e=o.match(/^(?:rm|remove|del|delete)\s+(\d+)$/);if(e){const o=so(Number(e[1]));return console.log(),console.log(o?chalk.gray(` Removed draft #${e[1]}.`):chalk.yellow(` No draft #${e[1]}.`)),console.log(),void le.prompt()}const t=W(),n=ao(t?.session?.examId??null);if(console.log(),0===n.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 n){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 le.prompt()}if("menu"===l||"menu confirm"===l)return Y()&&"menu confirm"!==l?(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 le.prompt()):void C(le);if(S()){ae=!0;const o=await O(l);return ae=!1,"exit"===o&&le.setPrompt(Bo()),void le.prompt()}if(N()){ae=!0;const o=await L(l);return ae=!1,"exit"!==o&&"solved"!==o||le.setPrompt(Bo()),void le.prompt()}if(D()){ae=!0;const o=await P(l);return ae=!1,"exit"===o&&le.setPrompt(Bo()),le.setPrompt(D()?chalk.bold.cyan("icoa ctf4eai> "):Bo()),void le.prompt()}if(ho(l),"exit"===l)return W()?(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 le.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"===te&&Ho(),void le.prompt());if("quit"===l||"q"===l||"quit confirm"===l){const o=W();return o&&"demo-free"!==o.session.examId&&"quit confirm"!==l?(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 le.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)."))),fo(),xo(),Ao(),oo(),f(),console.log(chalk.gray(" Session saved. Use ")+chalk.white("icoa --resume")+chalk.gray(" to continue.")),io(),void i(0))}if("back"===l){const o=W(),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=g();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"===te?Ho():console.log(chalk.gray(" Already at main menu."))}return void le.prompt()}if("help"===l||"?"===l){if(W()){ae=!0;try{await e.parseAsync(["node","icoa","exam","help"])}catch{}return ae=!1,void le.prompt()}return Ko(p(),te),void le.prompt()}if("man"===l||"manual"===l)return Ko(p(),te),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 le.prompt();if(/^(?:man|manual)\s+\S/i.test(l))return j(l.replace(/^(?:man|manual)\s+/i,"")),void le.prompt();if("more help"===l.toLowerCase()&&W()){ae=!0;try{await e.parseAsync(["node","icoa","exam","more-help"])}catch{}return ae=!1,void le.prompt()}if("continue"===l.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 le.prompt();if(/^ICOA-[A-Z]{2,3}-\d{1,6}$/i.test(l.trim())){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",l.trim()])}catch{}return ae=!1,void le.prompt()}if(/^[A-Z]{2}[0-9A-HJKMNP-TV-Z]{8}$/i.test(l.trim())){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",l.trim().toUpperCase()])}catch{}return ae=!1,void le.prompt()}const s=l.match(/^exam\s+([A-Z]{2}[0-9A-HJKMNP-TV-Z]{8})$/i);if(s){ae=!0;try{await e.parseAsync(["node","icoa","exam","token",s[1].toUpperCase()])}catch{}return ae=!1,void le.prompt()}const r=l.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 le.prompt()}const y=l.match(/^exam\s+(\S+)$/i);if(y&&!Zo.has(y[1].toLowerCase())){const o=y[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 le.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 le.prompt()}if("clear"===l||"cls"===l)return console.clear(),void le.prompt();if("news"===l)return $o()?Io():console.log(chalk.gray(" No competition joined. Use ")+chalk.white("join <url>")+chalk.gray(".")),void le.prompt();if("memo"===l){if(!$o())return console.log(chalk.gray(" Join a competition first: ")+chalk.white("join <url>")),void le.prompt();ae=!0;try{await No()}catch{}return void(ae=!1)}const m=So()||Eo(g().userName||"");if("jury"===l&&m){ae=!0;try{await Lo()}catch{}return void(ae=!1)}if(m&&So()&&"scoreboard"===l.split(/\s+/)[0]){ae=!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 ae=!1,void le.prompt()}if(m&&To()){const o=l.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 le.prompt()}if(l.startsWith("activate ")){const o=l.slice(9).trim(),e=await u(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 le.prompt()}if("activate"===l)return console.log(chalk.gray(" Usage: ")+chalk.white("activate <token>")),console.log(),void le.prompt();const d=W();if(d){const o=l.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)},n=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=X(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 l=d._lastQ||1;if(t(l))return a(l),void le.prompt();if(n(l))return console.log(),console.log(chalk.yellow(` Q${l} 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 ${l} 42`)+chalk.gray(")")),console.log(),void le.prompt();ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(l),o])}catch{}return ae=!1,void le.prompt()}if(/^-?\d+$/.test(o)){const t=d._lastQ||1;if(n(t)){ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",String(t),o])}catch{}return ae=!1,void le.prompt()}}const s=o.match(/^(\d+)\s+([ABCDE]|-?\d+)$/);if(s){const o=parseInt(s[1],10);if(t(o))return a(o),void le.prompt();ae=!0;try{await e.parseAsync(["node","icoa","exam","answer",s[1],s[2]])}catch{}return ae=!1,void le.prompt()}}const b=l.split(/\s+/)[0].toLowerCase(),x=/^python3?(\.\d+)?$/.test(b),v="ls"===b||"pwd"===b||"tmux"===b,k=l.startsWith("!")||b.startsWith("!")||x||v,A=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"]),I=()=>{console.log(chalk.gray(" Shell commands need ")+chalk.bold.cyan("!")+chalk.gray(" prefix. Try: ")+chalk.bold.cyan(`!${l}`)),console.log()};if("py"===b||"pylist"===b)return console.log(chalk.yellow(` ${b} 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"===b?"/py":"/pylist")+chalk.gray(" on any card.")),console.log(),void le.prompt();if("embodied"===te&&!k&&!["doctor","demo2","learn","exam","ctf4eai","ctf4vla","eai","arena","lang","ref","setup","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(b))return A.has(b)?(I(),void le.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 le.prompt());if("selection"===te&&!k&&!["doctor","exam","demo","demo2","demo4","demo5","retry","nations","next","prev","continue","setup","lang","ref","ai4ctf","ctf4ai","mark","unmark","review","submit","env","aienv","ipynb","kaggle","teleload","pandahelpme31","guide","board","sim"].includes(b)){if(A.has(b))return I(),void le.prompt();if(n().includes(b))console.log(chalk.gray(` ${b} isn't available on this screen.`));else{console.log(chalk.yellow(` Unknown command: ${b}`));const o=nearestCommand(b);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 le.prompt()}if("organizer"===te&&!["doctor","join","exam","demo","retry","next","prev","logout","setup","lang","ref","ctf","mark","unmark","review","submit","tmux"].includes(b))return console.log(chalk.gray(" Not available in Organizer mode. Switch via: setup")),console.log(),void le.prompt();if(!("olympiad"!==te||p()&&w()||h(b)))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 le.prompt();if(!n().includes(b)){if("tmux"===b)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 le.prompt()}if(Yo.has(b))return console.log(chalk.yellow(` "${b}" 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(`!${l}`)),console.log(),void le.prompt();if(/(?:^|\s)(?:\/(?!home\/|Users\/|tmp\/)|\.\.\/|~\/)/.test(l)&&!l.startsWith("cd ")){const o=/(?:^|\s)\/(?!home\/\w+\/icoa-workspace|Users\/\w+\/icoa-workspace|tmp\/)/.test(l),e=/\.\./.test(l);if(o||e)return console.log(chalk.red(" Blocked: access outside workspace is not allowed.")),console.log(chalk.gray(` Workspace: ${Wo}`)),console.log(),void le.prompt()}let o=l.startsWith("!")?l.slice(1).trim():l;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=uo(),n=mo(l);po({cwd:e,input:l,riskFlags:n}),n.length>0&&Y()&&(console.log(chalk.yellow(` β Action flagged: ${n.join(", ")} β logged.`)),console.log()),/^(\S*python3?(\.\d+)?)\s*$/.test(o)&&(o=`PYTHONSTARTUP="${function(){const o=Fo(Ro(),".icoa");Do(o)||Po(o,{recursive:!0});const e=Fo(o,"python-startup.py");let t="";if(Do(e))try{t=Mo(e,"utf-8")}catch{}return t!==Uo&&qo(e,Uo),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 yo()&&await co()?await go(o,le):await Go(o,le,e)}catch{console.log(chalk.yellow(` Command failed: ${b}`))}return ae=!1,console.log(),void le.prompt()}ae=!0;const $=l.trim(),T=$.toLowerCase();let E,q=null,R="";if(d)if("submit"===T)q="final";else if(T.startsWith("submit ")){let o=$.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)?(q="flag",R=o):o&&/^[ABCDE]$/i.test(o)&&(q="flag",R=o.toUpperCase())}else/^ICOA\{[^}]+\}$/i.test($)&&(q="flag",R=$);E="final"===q?["exam","submit"]:"flag"===q?["exam","answer",String(d?._lastQ||1),R]:mapCommand(l);const U="ctf"===E[0]&&"join"===E[1];U&&le.pause(),process.exit=()=>{throw new Error(Qo)};try{await e.parseAsync(["node","icoa",...E])}catch(o){const e=o instanceof Error?o.message:String(o);if(e===Qo);else if(e.includes("commander.unknownCommand")){const o=nearestCommand(b.split(/\s+/)[0]||b);console.log(chalk.yellow(` Unknown command: ${b}.`)),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"===b||"flag"===b?(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: ${b}`)),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=i,ae=!1,U&&le.resume()}S()?le.setPrompt(chalk.magenta("icoa ai4ctf> ")):N()?le.setPrompt(chalk.red("icoa ctf4ai> ")):D()&&le.setPrompt(chalk.bold.cyan("icoa ctf4eai> ")),console.log(),le.prompt()}),le.on("SIGINT",()=>{if(console.log(),S()||N())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(W()){const o="demo-free"!==W().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(),le.prompt()}),le.on("close",()=>{fo(),xo(),Ao(),oo(),f(),io(),i(0)}),"1"===process.env.ICOA_AUTO_RESUME&&(delete process.env.ICOA_AUTO_RESUME,z()&&(ae=!0,await Vo(e),ae=!1,le.setPrompt(S()?chalk.magenta("icoa ai4ctf> "):Bo()),le.prompt()))}function Go(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{}ko(),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 Ko(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 l(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.
|
|
3
|
+
"version": "2.19.490",
|
|
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": {
|