icoa-cli 2.19.628 → 2.19.629

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.
@@ -0,0 +1 @@
1
+ import chalk from"chalk";import{lazyJson as t}from"./lazy-assets.js";export async function loadReplay(e){const s=await t(`replays/aio${e}.json`,8e3);return s&&1===s.v&&Array.isArray(s.frames)&&s.frames.length>0?s:null}export const REPLAY_MIN_COLS=120;const e=new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`,"g"),s=(t,s)=>t+" ".repeat(Math.max(0,s-(t=>[...t.replace(e,"")].length)(t))),i=(t,e)=>{const s=[];let i="";for(const n of t.split(/\s+/).filter(Boolean))i&&i.length+1+n.length>e?(s.push(i),i=n):i=i?`${i} ${n}`:n;return i&&s.push(i),s};export class ReplayPlayer{doc;opts;i=0;lang="python";steps;extra=null;constructor(t,e){this.doc=t,this.opts=e,this.steps=[...t.frames],t.summary?.idea?.length&&this.steps.push({left:[],line:null,vars:{},verdict:"ok",summary:!0,key:"Last step — the whole idea on one screen, key lines marked ◆. Ask about anything: /ai what does line 5 do"})}static tooNarrow(){return(process.stdout.columns??120)<120}start(t){"cpp"===t&&this.doc.code.cpp&&(this.lang="cpp"),this.render()}code(){return"cpp"===this.lang&&this.doc.code.cpp?this.doc.code.cpp:this.doc.code.python}highlight(t){return null==t.line?new Set:"cpp"===this.lang?new Set((this.doc.map[String(t.line+1)]??[]).map(t=>t-1)):new Set([t.line])}keyLines(){return("cpp"===this.lang?this.doc.summary?.cpp:this.doc.summary?.python)??[]}drawSummary(){const t=[chalk.bold.green("SUMMARY")+chalk.gray(" the idea")];for(const e of this.doc.summary.idea){const s=i(e,59);t.push(chalk.green("• ")+chalk.white(s[0]??""),...s.slice(1).map(t=>` ${chalk.white(t)}`),"")}t.push(chalk.bold.green("THE CODE")+chalk.gray(" what makes it work in "+("cpp"===this.lang?"C++":"Python")));for(const[e,s]of this.keyLines()){const n=i(s,52);t.push(`${chalk.green("◆ ")}${chalk.bold.cyan(`line ${String(e).padEnd(2)}`)} ${chalk.white(n[0]??"")}`,...n.slice(1).map(t=>` ${chalk.white(t)}`))}return t}rightPanel(t,e,s){const i=this.code(),n=this.highlight(t),o=t.summary?new Set(this.keyLines().map(([t])=>t-1)):new Set,h=[...n.size?n:o].sort((t,e)=>t-e);let r=0,a=i.length;if(s&&i.length>s){const t=h.length?Math.floor(((h[0]??0)+(h[h.length-1]??0))/2):0;r=Math.max(0,Math.min(t-Math.floor(s/2),i.length-s)),a=r+s}const l="cpp"===this.lang?"C++":"Python",c=[chalk.gray("─ ")+chalk.bold.white(l)+chalk.gray(` ${"─".repeat(54-l.length-3)}`)];r>0&&c.push(chalk.gray(` ⋮ ${r} line${r>1?"s":""} above`));for(let t=r;t<a;t++){const e=`${String(t+1).padStart(2)} `,s=i[t]??"";n.has(t)?c.push(chalk.bold.yellow(`▸${e}${s}`)):o.has(t)?c.push(chalk.green("◆")+chalk.bold.cyan(e)+chalk.white(s)):c.push(chalk.gray(` ${e}${s}`))}a<i.length&&c.push(chalk.gray(` ⋮ ${i.length-a} more line${i.length-a>1?"s":""}`));const p=t.vars??{},d=Object.keys(p);if(d.length){c.push(chalk.gray(`─ variables ${"─".repeat(42)}`));for(const t of d){let s=String(p[t]);s.length>54-t.length-6&&(s=`${s.slice(0,54-t.length-9)}...`);const i=null!==e&&(!(t in(e.vars??{}))||e.vars[t]!==p[t]);c.push(` ${chalk.cyan(t)} = ${i?chalk.yellow(s):chalk.white(s)}`)}}return c}footer(){const t=this.i===this.steps.length-1,e=[chalk.bold.green("[Enter]")+chalk.gray(t?" finish":" next"),chalk.bold.cyan("[b]")+chalk.gray(" back")];return this.doc.code.cpp&&e.push("cpp"===this.lang?chalk.bold.cyan("[p]")+chalk.gray(" Python code"):chalk.bold.cyan("[c]")+chalk.gray(" C++ code")),e.push(chalk.bold.magenta("[/ai]")+chalk.gray(" 🐼 ask about this step or a line")),e.push(chalk.bold.cyan("[q]")+chalk.gray(" back to the card")),e.join(" ")}render(){const t=this.steps[this.i],e=this.i>0?this.steps[this.i-1]:null,n=t.summary?this.drawSummary():[...t.left],o=i(t.key,116),h=Object.keys(t.vars??{}).length,r=this.extra?this.extra.length+2:0,a=process.stdout.rows??0,l=a?Math.max(8,a-2-1-o.length-1-2-1-r-(h?h+1:0)-3):null,c=this.rightPanel(t,e,l),p=Math.max(n.length,c.length);for(;n.length<p;)n.push("");for(;c.length<p;)c.push("");const d=this.steps.length,g=Math.round(12*(this.i+1)/d),y=chalk.white(`step ${this.i+1}/${d} `)+chalk.green("▰".repeat(g))+chalk.gray("▱".repeat(12-g))+(t.summary?chalk.bold.green(" summary"):""),u=/(.*?card \d+)/.exec(this.doc.source)?.[1]??this.doc.source,m=[`${chalk.bold.white(this.doc.title)}${chalk.gray(` ${u}`)} ${y}`,""];for(let t=0;t<p;t++)m.push(`${s(n[t]??"",62)} ${c[t]??""}`);m.push("");const f="ok"===t.verdict?chalk.green:"no"===t.verdict?chalk.red:chalk.white;for(const[t,e]of o.entries())m.push(chalk.bold.yellow(0===t?"▸ ":" ")+f(e));if(this.extra){m.push("");for(const t of this.extra)m.push(` ${chalk.white(t)}`)}m.push("",this.footer()),process.stdout.isTTY&&process.stdout.write(""),console.log(m.join("\n")),this.extra=null}async handle(t){const e=t.trim(),s=e.toLowerCase();if(["q","quit","exit","back to card","card"].includes(s))return"done";if(s.startsWith("/ai")||s.startsWith("ai ")){const t=e.replace(/^\/?ai\s*/i,"");return t?(await this.opts.ask(this.question(t)),console.log(chalk.gray(" ▸ ")+chalk.bold.green("Enter")+chalk.gray(" next step · b back · q back to the card")),"input"):(this.extra=["Ask about this step or any line of the code on screen, for example:"," /ai what does line 5 do /ai why is this step red"],this.render(),"input")}if("c"===s||"c++"===s||"cpp"===s)this.doc.code.cpp?"cpp"===this.lang?this.extra=["Already showing C++. Press p for Python."]:this.lang="cpp":this.extra=["No C++ view for this replay yet."];else if("p"===s||"py"===s||"python"===s)"python"===this.lang?this.extra=["Already showing Python."+(this.doc.code.cpp?" Press c for C++.":"")]:this.lang="python";else if("b"===s||"back"===s)0===this.i&&(this.extra=["This is the first step. q goes back to the card."]),this.i=Math.max(0,this.i-1);else if(""===s||"n"===s||"next"===s||"ok"===s){if(this.i>=this.steps.length-1)return"done";this.i++}else this.extra=[`"${e}" is not a replay key. Enter next · b back · ${"cpp"===this.lang?"p Python":"c C++"} · /ai <question> · q back to the card`];return this.render(),"input"}question(t){const e=this.steps[this.i],s=this.code(),i=new Set;for(const e of t.matchAll(/(?:line|l|第)\s*(\d+)/gi)){const t=Number(e[1]);t>=1&&t<=s.length&&i.add(t)}for(const t of this.highlight(e))i.add(t+1);const n="cpp"===this.lang?this.doc.notes.cpp:this.doc.notes.python,o=[...i].sort((t,e)=>t-e).slice(0,6).map(t=>`line ${t}: ${s[t-1]?.trim()} — ${n[String(t)]??""}`);return[`[Replay of ${this.doc.title} (${this.doc.source}), ${"cpp"===this.lang?"C++":"Python"} view, step ${this.i+1}/${this.steps.length}: ${e.key}]`,...o,`Question: ${t}`].join("\n").slice(0,1900)}}
@@ -1 +1 @@
1
- import{getDeviceFingerprint as e}from"./access.js";import{LEARN_SERVER as t}from"./learn-curricula.js";async function n(n,r,o){const a=t.replace(/\/$/,"")+n;try{const t=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...r,device_fingerprint:e()}),signal:AbortSignal.timeout(o)}),n=await t.json().catch(()=>({}));return t.ok&&n.success&&void 0!==n.data?{ok:!0,data:n.data}:{ok:!1,message:n.message||`HTTP ${t.status}`,code:n.code,wait_s:n.wait_s}}catch(e){return{ok:!1,message:`Network error: ${e instanceof Error?e.message:String(e)}`}}}export function learnPost(e,t,r){return n(e,t,r)}export function contestStart(e,t,r,o){return n("/api/icoa/learn/contest/start",{token:e.toUpperCase(),phase:t,...null!=r?{slot:r}:{},...o?{practice:!0}:{}},15e3)}export function contestSubmit(e,t,r,o,a,s){return n("/api/icoa/learn/contest/submit",{token:e.toUpperCase(),phase:t,problem_id:r,code:o,...null!=a?{slot:a}:{},...s?{dyn:s}:{}},12e4)}export function contestReset(e,t,r){return n("/api/icoa/learn/contest/reset",{token:e.toUpperCase(),phase:t,...null!=r?{slot:r}:{}},15e3)}export function duckBoard(e,t,r={}){return n("/api/icoa/learn/duck/board",{token:e.toUpperCase(),problem_id:t,...r},15e3)}export function fetchGate(e){return n("/api/icoa/learn/gate",{token:e.toUpperCase()},3e4)}export function learnCheck(e,t){return n("/api/icoa/learn/check",{token:e.toUpperCase(),target:t.toUpperCase()},15e3)}export function learnRoster(e,t){return n("/api/icoa/learn/roster",{token:e.toUpperCase(),...t?{cohort:t}:{}},2e4)}export function linkSuggest(e){return n("/api/icoa/learn/link",{token:e.toUpperCase()},2e4)}export function linkByIndex(e,t){return n("/api/icoa/learn/link",{token:e.toUpperCase(),index:t},2e4)}export function linkToken(e,t){return n("/api/icoa/learn/link",{token:e.toUpperCase(),other_token:t.toUpperCase()},2e4)}export function timeLeft(e){const t=Date.parse(e);if(Number.isNaN(t))return null;const n=t-Date.now();if(n<=0)return null;const r=Math.floor(n/6e4),o=Math.floor(n%6e4/1e3);return`${r}:${String(o).padStart(2,"0")}`}export function arenaSlotAtPos(e){return e%4==0?e/4:10===e?4:0}export function arenaPosInPhase(e){const t=[];for(let n=4;n<=Math.min(e,12);n+=4)t.push(n);return t}export function arenaCadence(e=12){const t=arenaPosInPhase(e);return{cards:t.join(" / "),n:t.length}}export function posForArenaSlot(e){return 4===e?10:4*e}export function quizShape(e){const t=e.statement??"",n=/Answer with ONE of:\s*([^\n]+)/.exec(t);if(n){const e=n[1].split("/").map(e=>e.trim()).filter(Boolean);if(e.length>=2)return{kind:"choose",options:e}}return/^\s*Answer:\s*____/m.test(e.starter??"")||/Type the letter/i.test(t)?{kind:"letter"}:{kind:"value"}}export function fillQuizAnswer(e,t,n){const r=n.trim();if(e?.includes("____"))return e.replace("____",r);const o=/^(\s*Answer:\s*)(?:____|[^\n]*)$/m;return o.test(t)?t.replace(o,`$1${r}`):t.includes("____")?t.replace("____",r):`${t.replace(/\s*$/,"")}\nAnswer: ${r}\n`.replace(/^\n/,"")}
1
+ import{getDeviceFingerprint as e}from"./access.js";import{LEARN_SERVER as t}from"./learn-curricula.js";async function n(n,r,o){const a=t.replace(/\/$/,"")+n;try{const t=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...r,device_fingerprint:e()}),signal:AbortSignal.timeout(o)}),n=await t.json().catch(()=>({}));return t.ok&&n.success&&void 0!==n.data?{ok:!0,data:n.data}:{ok:!1,message:n.message||`HTTP ${t.status}`,code:n.code,wait_s:n.wait_s}}catch(e){return{ok:!1,message:`Network error: ${e instanceof Error?e.message:String(e)}`}}}export function learnPost(e,t,r){return n(e,t,r)}export function contestStart(e,t,r,o){return n("/api/icoa/learn/contest/start",{token:e.toUpperCase(),phase:t,...null!=r?{slot:r}:{},...o?{practice:!0}:{}},15e3)}export function contestSubmit(e,t,r,o,a,s,i){return n("/api/icoa/learn/contest/submit",{token:e.toUpperCase(),phase:t,problem_id:r,code:o,...null!=a?{slot:a}:{},...s?{dyn:s}:{},...i?{lang:i}:{}},12e4)}export function contestReset(e,t,r){return n("/api/icoa/learn/contest/reset",{token:e.toUpperCase(),phase:t,...null!=r?{slot:r}:{}},15e3)}export function duckBoard(e,t,r={}){return n("/api/icoa/learn/duck/board",{token:e.toUpperCase(),problem_id:t,...r},15e3)}export function fetchGate(e){return n("/api/icoa/learn/gate",{token:e.toUpperCase()},3e4)}export function learnCheck(e,t){return n("/api/icoa/learn/check",{token:e.toUpperCase(),target:t.toUpperCase()},15e3)}export function learnRoster(e,t){return n("/api/icoa/learn/roster",{token:e.toUpperCase(),...t?{cohort:t}:{}},2e4)}export function linkSuggest(e){return n("/api/icoa/learn/link",{token:e.toUpperCase()},2e4)}export function linkByIndex(e,t){return n("/api/icoa/learn/link",{token:e.toUpperCase(),index:t},2e4)}export function linkToken(e,t){return n("/api/icoa/learn/link",{token:e.toUpperCase(),other_token:t.toUpperCase()},2e4)}export function timeLeft(e){const t=Date.parse(e);if(Number.isNaN(t))return null;const n=t-Date.now();if(n<=0)return null;const r=Math.floor(n/6e4),o=Math.floor(n%6e4/1e3);return`${r}:${String(o).padStart(2,"0")}`}export function arenaSlotAtPos(e){return e%4==0?e/4:10===e?4:0}export function arenaPosInPhase(e){const t=[];for(let n=4;n<=Math.min(e,12);n+=4)t.push(n);return t}export function arenaCadence(e=12){const t=arenaPosInPhase(e);return{cards:t.join(" / "),n:t.length}}export function posForArenaSlot(e){return 4===e?10:4*e}export function quizShape(e){const t=e.statement??"",n=/Answer with ONE of:\s*([^\n]+)/.exec(t);if(n){const e=n[1].split("/").map(e=>e.trim()).filter(Boolean);if(e.length>=2)return{kind:"choose",options:e}}return/^\s*Answer:\s*____/m.test(e.starter??"")||/Type the letter/i.test(t)?{kind:"letter"}:{kind:"value"}}export function fillQuizAnswer(e,t,n){const r=n.trim();if(e?.includes("____"))return e.replace("____",r);const o=/^(\s*Answer:\s*)(?:____|[^\n]*)$/m;return o.test(t)?t.replace(o,`$1${r}`):t.includes("____")?t.replace("____",r):`${t.replace(/\s*$/,"")}\nAnswer: ${r}\n`.replace(/^\n/,"")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.628",
3
+ "version": "2.19.629",
4
4
  "description": "ICOA CLI — AI-native competition runtime of the International Cyber Olympiad in AI: learn, practise, and compete in AI & cybersecurity from the terminal (AI4CTF · CTF4AI · CTF4EAI)",
5
5
  "author": "Charlie Zhu",
6
6
  "type": "module",