icoa-cli 2.19.562 → 2.19.563
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/learn-flow.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{appendFileSync as t,mkdirSync as s}from"node:fs";import{homedir as i}from"node:os";import{join as h}from"node:path";import chalk from"chalk";const r=new Set(["back","b","quit","q","exit"]);function
|
|
1
|
+
import{appendFileSync as t,mkdirSync as s}from"node:fs";import{homedir as i}from"node:os";import{join as h}from"node:path";import chalk from"chalk";const r=new Set(["back","b","quit","q","exit"]);function e(t,s=" "){const i=Math.max(40,Math.min(process.stdout.columns||80,100))-s.length-2,h=[];for(const r of t.split("\n")){const t=r.replace(/\s+$/,"");if(""===t.trim()){h.push("");continue}let e="";for(const r of t.split(" ")){const t=e?`${e} ${r}`:r;if(t.length<=i)e=t;else{e&&h.push(s+e);let t=r;for(;t.length>i;)h.push(s+t.slice(0,i)),t=t.slice(i);e=t}}e&&h.push(s+e)}return h}export class FlowRunner{cardNumber;steps;zh;print;idx=0;fork=null;forkRec=null;forkShownAt=0;askStep=null;askMisses=0;recs=[];forkNo=0;constructor(t){this.steps=t.steps,this.zh=t.zh,this.cardNumber=t.cardNumber,this.print=t.print}start(){return this.print(""),this.print(chalk.gray(" ")+chalk.bold.magenta(this.zh?"⚔ 互动流程":"⚔ Interactive walk")+chalk.gray(this.zh?" — 每一步都要你动手;选错不扣分,墙上写着为什么。":" — every step asks you; a wrong turn costs nothing, the wall says why.")),this.print(chalk.gray(this.zh?" (back 退出流程回到卡片)":" (back leaves the walk and returns to the card)")),this.print(""),this.advance()}records(){return this.recs.slice()}handle(t){const s=t.trim(),i=s.toLowerCase();return this.fork&&this.resolveChoice(s,this.fork)?this.handleFork(s):r.has(i)?"exit":this.fork?this.handleFork(s):this.askStep?this.handleAsk(s):this.advance()}handleAsk(t){const s=this.askStep;if(""===t)return this.askMisses++,this.askMisses>=2&&(this.zh?s.hint_zh:s.hint_en)?this.print(chalk.gray(" "+(this.zh?"提示:":"hint: ")+(this.zh?s.hint_zh:s.hint_en))):this.print(chalk.gray(this.zh?" 写下你的想法(哪怕只有一个词),或敲 skip 直接看。":" Write your thought (one word is fine), or type skip to see it.")),"input";this.askStep=null,this.askMisses=0;const i=this.zh?s.reveal_zh:s.reveal_en;this.print("");for(const t of e(i," "))this.print(chalk.white(t));return this.print(""),this.advance()}handleFork(t){const s=this.fork,i=this.forkRec,h=this.resolveChoice(t,s);if(!h){const t=s.opts.map(t=>t.k).join(" / ");return this.print(chalk.gray(" "+(this.zh?`请选 ${t}(或 back 退出)`:`Choose ${t} (or back to leave)`))),"input"}i.choices.push(h.k),i.first||(i.first=h.k),this.print(""),this.print(chalk.gray(" ▸ ")+chalk.white(this.zh?`你选了 ${h.k}。`:`You chose ${h.k}.`));const r=this.zh?h.text_zh:h.text_en;if(r)for(const t of e(r," "))this.print(chalk.white(t));return"wall"===h.kind?(i.walls++,this.print(""),this.print(chalk.yellow(" 🧭 ")+chalk.gray(this.zh?"回到这个分叉,重选。":"Back to this fork — choose again.")),this.printForkOptions(s),"input"):(i.final=h.k,i.ms=Date.now()-this.forkShownAt,this.recs.push(i),this.fork=null,this.forkRec=null,"ok"===h.kind&&this.print(chalk.green(" ✅ ")+chalk.gray(this.zh?"也是一条满分路。":"Also a full-mark route.")),this.print(""),this.advance())}resolveChoice(t,s){const i=t.trim().toLowerCase();if(!i)return null;const h=s.opts.find(t=>t.k.toLowerCase()===i);if(h)return h;const r=Number.parseInt(i,10);if(Number.isInteger(r)&&r>=1&&r<=s.opts.length)return s.opts[r-1];const e=/^(?:option|choose|pick|选|选择)?\s*([a-c])\b/.exec(i);if(e)return s.opts.find(t=>t.k.toLowerCase()===e[1])??null;const n=i.split(/\s+/)[0],o=s.opts.filter(t=>(this.zh?t.zh:t.en).toLowerCase().startsWith(n));return 1===o.length?o[0]:null}printForkOptions(t){this.print("");for(const s of t.opts){const t=e(this.zh?s.zh:s.en," ");this.print(chalk.bold.cyan(` ${s.k} `)+chalk.white(t[0]?.trimStart()??""));for(const s of t.slice(1))this.print(chalk.white(s))}this.print(""),this.print(chalk.gray(" "+(this.zh?"你选哪条? ":"Your move? ")+t.opts.map(t=>t.k).join(" / ")))}advance(){for(;this.idx<this.steps.length;){const t=this.steps[this.idx++];switch(t.t){case"text":for(const s of e(this.zh?t.zh:t.en))this.print(chalk.white(s));this.print("");break;case"mother":this.print(chalk.bold.yellow(" ▶ "+(this.zh?"母题":"MOTHER PROBLEM")));for(const s of e(this.zh?t.zh:t.en," "))this.print(chalk.white(s));this.print("");break;case"ask":this.print(chalk.bold.cyan(" 🎯 GUESS N CHECK"));for(const s of e(this.zh?t.zh:t.en," "))this.print(chalk.white(s));return this.print(chalk.gray(" "+(this.zh?"> 写下你的答案(不判分):":"> your answer (not graded):"))),this.askStep=t,"input";case"fork":this.forkNo++,this.print(chalk.bold.magenta(` ⚔ ${this.zh?"分叉":"FORK"} ${this.forkNo}`));for(const s of e(this.zh?t.zh:t.en," "))this.print(chalk.white(s));return this.fork=t,this.forkRec={fork_id:t.id,first:"",final:"",walls:0,ms:0,choices:[],started_at:(new Date).toISOString()},this.forkShownAt=Date.now(),this.printForkOptions(t),"input";case"review":this.print(chalk.bold.yellow(" 🧭 "+(this.zh?"复盘":"REVIEW")));for(const t of this.pathSummary())this.print(chalk.gray(" "+t));this.print("");for(const s of e(this.zh?t.zh:t.en," "))this.print(chalk.white(s));this.print("");break;case"rule":this.print(chalk.bold.green(" 💡 "+(this.zh?"举一反三 · 迁移判据":"TRANSFER — same idea, next problem")));for(const s of e(this.zh?t.zh:t.en," "))this.print(chalk.white(s));this.print("");break;case"extend":this.print(chalk.bold.cyan(" 🔗 "+(this.zh?"延展 — 母题讲完,同一招再走一步":"EXTEND — same idea, one step further")));for(const s of e(this.zh?t.zh:t.en," "))this.print(chalk.white(s));this.print("");break;case"stretch":this.print(chalk.bold.white(" ⭐ "+(this.zh?"拔高(可选,不判分)":"STRETCH (optional, not graded)")));for(const s of e(this.zh?t.zh:t.en," "))this.print(chalk.gray(s));this.print("")}}return this.spool(),"done"}pathSummary(){return this.recs.map((t,s)=>{const i=t.choices.join(" → "),h=t.walls?this.zh?` · 撞墙 ${t.walls} 次`:` · ${t.walls} wall${t.walls>1?"s":""}`:"";return`${this.zh?"分叉":"Fork"} ${s+1}: ${i}${h}`})}spool(){try{const r=h(i(),".icoa");s(r,{recursive:!0});for(const s of this.recs)t(h(r,"learn-flow.jsonl"),JSON.stringify({card:this.cardNumber,...s})+"\n")}catch{}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "icoa-cli",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.563",
|
|
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",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"cli-table3": "^0.6.5",
|
|
53
53
|
"commander": "^13.1.0",
|
|
54
54
|
"fastest-levenshtein": "^1.0.16",
|
|
55
|
+
"icoa-cli": "^2.19.562",
|
|
55
56
|
"marked": "^15.0.7",
|
|
56
57
|
"marked-terminal": "^7.3.0",
|
|
57
58
|
"ora": "^8.2.0",
|