icoa-cli 2.19.634 → 2.19.636
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/README.md +7 -0
- package/dist/commands/ai4ctf.js +1 -1
- package/dist/commands/ctf4ai-demo.js +1 -1
- package/dist/commands/ctf4vla.js +1 -1
- package/dist/commands/exam.js +1 -1
- package/dist/commands/learn.js +1 -1
- package/dist/lib/learn-curricula.js +1 -1
- package/dist/lib/learn-pvp.js +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
export function localized(e,t){const r=(t||"en").slice(0,2).toLowerCase();if("en"===r)return e;const n=e[`_${r}`];if(!n||"object"!=typeof n)return e;const a=n,o={...e};for(const e of Object.keys(a))void 0!==a[e]&&(o[e]=a[e]);return o}export function overlayLanguages(e){const t=new Set;for(const r of e)for(const e of Object.keys(r)){const r=/^_([a-z]{2})$/.exec(e);r&&"en"!==r[1]&&t.add(r[1])}return[...t].sort()}export function isValidCurriculum(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.id&&"number"==typeof t.totalCards&&Array.isArray(t.cards)&&Array.isArray(t.modules)}import{readFileSync as e,writeFileSync as t,mkdirSync as r,existsSync as n,statSync as a,utimesSync as o}from"node:fs";import{join as
|
|
1
|
+
export function localized(e,t){const r=(t||"en").slice(0,2).toLowerCase();if("en"===r)return e;const n=e[`_${r}`];if(!n||"object"!=typeof n)return e;const a=n,o={...e};for(const e of Object.keys(a))void 0!==a[e]&&(o[e]=a[e]);return o}export function overlayLanguages(e){const t=new Set;for(const r of e)for(const e of Object.keys(r)){const r=/^_([a-z]{2})$/.exec(e);r&&"en"!==r[1]&&t.add(r[1])}return[...t].sort()}export function isValidCurriculum(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.id&&"number"==typeof t.totalCards&&Array.isArray(t.cards)&&Array.isArray(t.modules)}import{readFileSync as e,writeFileSync as t,mkdirSync as r,existsSync as n,statSync as a,utimesSync as o}from"node:fs";import{join as c}from"node:path";import{homedir as i}from"node:os";import{getDeviceFingerprint as s}from"./access.js";import{getCliVersion as u}from"./version.js";import{httpFetch as l}from"./http.js";import{transportAdvice as d,transportCauseCode as p}from"./tls-trust.js";import{parseHometask as f}from"./learn-hometask.js";import{parseFaqs as m,parseReplies as _}from"./learn-replies.js";const g=c(i(),".icoa","learn-cache");export const LEARN_SERVER=process.env.ICOA_LEARN_SERVER||"https://practice.icoa2026.au";function y(e){const t=e.replace(/[^A-Za-z0-9_-]/g,"_");return c(g,`${t}.json`)}function h(e){const t=e.replace(/[^A-Za-z0-9_-]/g,"_");return c(g,`${t}.etag`)}let E=null;export function getLastCurriculumFailure(){return E}export async function loadCurriculumById(c,i,s=!1){"ctf4eai-12"===c&&(c="LEARNDEMO01");const l=function(t){const r=y(t);if(!n(r))return null;try{const t=a(r),n=Date.now()-t.mtimeMs;return{curriculum:JSON.parse(e(r,"utf-8")),ageMs:n}}catch{return null}}(c);if(!s&&l&&l.ageMs<6048e5&&isValidCurriculum(l.curriculum))return l.curriculum;E=null;const d=await async function(t,r){const a=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/curriculum/"+encodeURIComponent(t),o={},c=function(t){const r=h(t);if(!n(r))return null;try{return e(r,"utf-8").trim()||null}catch{return null}}(t);c&&(o["If-None-Match"]=c),r&&(o["X-Learn-Token"]=r.toUpperCase()),o["X-ICOA-Client"]=u();try{const e=await fetch(a,{headers:o,signal:AbortSignal.timeout(6e4)});if(304===e.status)return{kind:"unchanged"};if(404===e.status)return{kind:"notfound"};if(!e.ok)return{kind:"error"};const t=await e.json();if(!t.success||!t.data)return{kind:"error"};if(!isValidCurriculum(t.data))return{kind:"error"};const r=e.headers.get("etag")||e.headers.get("ETag")||void 0;return{kind:"fresh",curriculum:t.data,etag:r||void 0}}catch{return{kind:"error"}}}(c,i);return"fresh"===d.kind?(function(e,n,a){try{r(g,{recursive:!0}),t(y(e),JSON.stringify(n)),a&&t(h(e),a)}catch{}}(c,d.curriculum,d.etag),d.curriculum):"unchanged"===d.kind&&l&&isValidCurriculum(l.curriculum)?(function(e){try{const t=y(e);if(n(t)){const e=Date.now()/1e3;o(t,e,e)}}catch{}}(c),l.curriculum):l&&isValidCurriculum(l.curriculum)?l.curriculum:(E="notfound"===d.kind?"notfound":"offline",null)}export function parseUpgradedTo(e){if(!e||"object"!=typeof e)return null;const t=e,r=String(t.token??"").toUpperCase(),n=String(t.curriculum_id??"");return/^[A-Z]{2}[A-Z0-9]{8}$/.test(r)&&n?{token:r,curriculumId:n}:null}export function validateResultShape(e){return{curriculumId:String(e.curriculum_id??""),status:String(e.status??""),validUntil:String(e.valid_until??""),aiEnabled:1===e.ai_enabled||!0===e.ai_enabled,aiBasicPerCard:"number"==typeof e.ai_basic_per_card&&e.ai_basic_per_card>0?e.ai_basic_per_card:3,gated:1===e.gated||!0===e.gated,replies:_(e.replies),hometask:f(e.hometask),upgradedTo:parseUpgradedTo(e.upgraded_to)}}export async function validateEAToken(e){const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/validate";try{const r=await l(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e.toUpperCase(),device_fingerprint:s()}),signal:AbortSignal.timeout(8e3)});if(!r.ok){const e=await r.json().catch(()=>({}));return{ok:!1,message:e.message||`HTTP ${r.status}`,code:e.code}}const n=await r.json();return n.success&&n.data?{ok:!0,...validateResultShape(n.data)}:{ok:!1,message:n.message||"Validation failed"}}catch(e){const t=e instanceof Error?e.message:String(e),r=p(e);return{ok:!1,message:`Network error: ${t}${r?` (${r})`:""}`,code:"network",advice:d(e)}}}export async function postFlowEvent(e,t,r,n){if("LEARNDEMO01"===e.toUpperCase())return;const a=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/flow/event";try{await l(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e.toUpperCase(),curriculum_id:t,card:r,fork_id:n.fork_id,first:n.first,final:n.final,walls:n.walls,ms:n.ms,choices:n.choices,started_at:n.started_at,device_fingerprint:s()}),signal:AbortSignal.timeout(5e3)})}catch{}}export async function syncProgress(e,t,r){if("LEARNDEMO01"===e.toUpperCase())return;const n=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/progress/"+e.toUpperCase();try{await l(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({card_number:t.card_number,event_type:t.event_type,mcq_answer:t.mcq_answer,mcq_correct:t.mcq_correct?1:0,check_answer:t.check_answer,check_correct:t.check_correct?1:0,time_on_card_ms:t.time_on_card_ms,device_fingerprint:s(),reply_ack:r&&r.length>0?r:void 0}),signal:AbortSignal.timeout(5e3)})}catch{}}export async function postFocusSession(e,t){if("LEARNDEMO01"===e.toUpperCase())return!0;const r=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/focus/"+e.toUpperCase();try{return(await l(r,{method:"POST",headers:{"Content-Type":"application/json","X-ICOA-Client":u()},body:JSON.stringify({...t,device_fingerprint:s()}),signal:AbortSignal.timeout(5e3)})).ok}catch{return!1}}export async function fetchServerProgress(e){if("LEARNDEMO01"===e.toUpperCase())return null;const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/progress/"+e.toUpperCase();try{const e=await l(t,{signal:AbortSignal.timeout(5e3)});if(!e.ok)return null;const r=await e.json();return r?.success&&Array.isArray(r.data?.events)?r.data.events:null}catch{return null}}export async function fetchCardFaqs(e){const t=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/faq/"+encodeURIComponent(e.toUpperCase());try{const e=await l(t,{signal:AbortSignal.timeout(5e3)});if(!e.ok)return[];const r=await e.json();return r.success&&r.data?m(r.data.faqs):[]}catch{return[]}}export async function syncCardFeedback(e,t){const r=LEARN_SERVER.replace(/\/$/,"")+"/api/icoa/learn/feedback/"+e.toUpperCase();try{return(await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({curriculum_id:t.curriculum_id,card_number:t.card_number,feedback_text:t.feedback_text,time_on_card_ms:t.time_on_card_ms}),signal:AbortSignal.timeout(5e3)})).ok}catch{return!1}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as o,readFileSync as e}from"node:fs";import{homedir as t}from"node:os";import{join as a}from"node:path";import chalk from"chalk";import{playSavedReplay as n,saveJudgeReplay as r}from"../commands/battle.js";import{getConfig as s}from"./config.js";import{learnPost as l}from"./learn-contest.js";export const PVP_RE=/^\/?(?:room|rooms|pvp|房间|对战房)(?:\s+(.*))?$/i;const c=(o,e,t={},a=2e4)=>l(`/api/icoa/learn/pvp/${o}`,{token:e.toUpperCase(),...t},a),i=()=>(s().language||"en").toLowerCase().startsWith("zh"),d=new Set(["back","b","quit","q","exit","card","lesson","卡片"]);export const DEFAULT_PVP_BOT=a(t(),".icoa","battleai","bot.py");const g=(o,e)=>o+" ".repeat(Math.max(0,e-[...o].length));function u(o){console.log(chalk.gray(i()?` up 上传 bot.py · vs <昵称> 挑战 · vs <昵称> v2 打对方旧版 · 回车/who 战绩表 · log 对局 · replay 看回放 · card 回卡片 (${o})`:` up upload bot.py · vs <nick> challenge · vs <nick> v2 an older version · Enter/who table · log matches · replay · card back to the card (${o})`))}function m(o){const e=i(),t=o.public?e?"公共房":"Open room":o.label||(e?"房间":"Room");console.log(),console.log(chalk.bold.white(` ⚔ ${t} `)+chalk.bold.cyan(o.room)+chalk.gray(` · ${e?"你是":"you are"} ${o.nick??"?"} · ${o.members.length} ${e?"人":"members"} · ${e?"今日":"today"} ${o.day}${o.public?e?" · 战绩每天清零":" · table resets daily":""}`)),console.log(chalk.gray(` ${g(e?"昵称":"nick",14)}${g("bot",6)}${g(e?"今日 胜-负-平":"today W-L-D",16)}${e?"累计":"all-time"}`));for(const e of o.members){const o=` ${g(e.nick,14)}${g(e.versions?`v${e.versions}`:"—",6)}${g(`${e.today.w}-${e.today.l}-${e.today.d}`,16)}${e.all.w}-${e.all.l}-${e.all.d}`;console.log(e.me?chalk.bold.cyan(o):chalk.white(o))}if(o.my_versions.length||console.log(chalk.yellow(e?" 你还没上传 bot —— 敲 up(默认发 ~/.icoa/battleai/bot.py)。":" You have no bot here yet — type up (sends ~/.icoa/battleai/bot.py).")),o.recent.length){console.log(chalk.gray(e?" 今日对局:":" Today:"));for(const e of o.recent.slice(0,6))console.log(chalk.gray(" ")+$(e))}}function $(o){const e="WIN"===o.verdict?chalk.green(`${o.wins_a}-${o.wins_b}`):"LOSS"===o.verdict?chalk.red(`${o.wins_a}-${o.wins_b}`):chalk.yellow(`${o.wins_a}-${o.wins_b}`),t=`${o.a} v${o.a_version??"?"} vs ${o.b} v${o.b_version??"?"}`;return`${chalk.gray((o=>{const e=new Date(o);return Number.isNaN(e.getTime())?"":`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`})(o.ts))} ${o.mine?chalk.white(t):chalk.gray(t)} ${e}${o.draws?chalk.gray(` (${o.draws} draw)`):""}${"WIN"!==o.verdict&&"LOSS"!==o.verdict&&"DRAW"!==o.verdict?chalk.red(` ${o.verdict}`):""}`}function y(o){const e=i();console.log();const t=`${o.wins_a}-${o.wins_b}${o.draws?` (${o.draws} ${e?"平":"draw"})`:""}`;if("WIN"===o.verdict)console.log(chalk.bold.green(` 🏆 ${e?"你赢了":"You win"} ${t}`)+chalk.gray(` vs ${o.opp.nick} v${o.opp.version}`));else if("LOSS"===o.verdict)console.log(chalk.bold.red(` ❌ ${e?"你输了":"You lose"} ${t}`)+chalk.gray(` vs ${o.opp.nick} v${o.opp.version}`));else{if("DRAW"!==o.verdict)return void console.log(chalk.yellow(` ⚠ ${e?"判分机没跑完这场":"The judge could not finish this match"}: ${o.verdict}${o.note?` — ${o.note}`:""}`));console.log(chalk.bold.yellow(` 🤝 ${e?"平局":"Draw"} ${t}`)+chalk.gray(` vs ${o.opp.nick} v${o.opp.version}`))}o.load_error?.a&&console.log(chalk.red(` ${e?"你的 bot 装不上":"Your bot failed to load"}: ${o.load_error.a}`)),o.load_error?.b&&console.log(chalk.gray(` ${e?"对方的 bot 装不上":"Opponent's bot failed to load"}: ${o.load_error.b}`)),console.log(chalk.gray(` ${g(e?"地图":"map",11)}${g(e?"席位":"seat",6)}${g(e?"结果":"result",8)}${g(e?"原因":"how",10)}${g(e?"回合":"turns",7)}${e?"损失 你/对方":"lost you/them"}`));for(const t of o.games){const o="a"===t.winner?e?"胜":"win":"b"===t.winner?e?"负":"loss":e?"平":"draw",a="a"===t.winner?chalk.green(g(o,8)):"b"===t.winner?chalk.red(g(o,8)):chalk.yellow(g(o,8)),n="warrens"===t.reason?e?"拆家":"warrens":"timeout"===t.reason?e?"超时":"timeout":"crash"===t.reason?e?"崩溃":"crash":"load_error"===t.reason?e?"装不上":"no load":e?"回合满":"turn cap";console.log(` ${g(t.map,11)}${g(String(t.seat_a),6)}${a}${g(n,10)}${g(String(t.turns),7)}${Math.round(t.lost[0])}/${Math.round(t.lost[1])}${t.error?chalk.gray(` ${t.error}`):""}`)}console.log(chalk.gray(` ${e?"种子":"seeds"} ${o.seeds.join(",")} · ${e?"回合满时比打掉的价值,躲家里不算赢":"at the turn cap the side that destroyed more value wins — hiding at home does not"}`)),o.replay&&r(o.replay)&&console.log(chalk.gray(" ▸ ")+chalk.bold.green("replay")+chalk.gray(o.wins_b?e?" 看你输掉的第一局":" watch the first game you lost":e?" 看第一局":" watch game 1"))}export async function runPvpRoom(t,a,r){const s=i(),l=r.trim();let h="",w="",f=!1;const v=/^(?:new|create|开房|建)(?:\s+(.*))?$/i.exec(l),k=/^(?:join|enter|进)\s+(\S+)$/i.exec(l);if(v?(f=!0,w=(v[1]??"").trim().slice(0,40)):k?h=k[1]:/^(?:open|public|公共)$/i.test(l)?h="OPEN":l&&(h=l),h=h.toUpperCase().replace(/[^A-Z0-9]/g,"").slice(0,8),!f&&!h){const o=await c("status",t);if(!o.ok||!o.data)return console.log(chalk.yellow(" "+p(o.code,o.message))),"back";if(console.log(),console.log(chalk.bold.white(s?" ⚔ PvP 房间":" ⚔ PvP rooms")+chalk.gray(s?" —— 和真人的 bot 对打,6 局定胜负。":" — your bot against real people, six games a match.")),o.data.rooms.length)for(const e of o.data.rooms)console.log(` ${chalk.bold.cyan(g(e.room,6))} ${chalk.white(g(e.public?s?"公共房":"open room":e.label||"",18))} ${chalk.gray(`${e.members} ${s?"人":"members"} · ${s?"你是":"you are"} ${e.nick}`)}`);else console.log(chalk.gray(s?" 你还没进过任何房间。":" You are not in any room yet."));return console.log(chalk.gray(" ▸ ")+chalk.bold.green("room open")+chalk.gray(s?" 公共房,谁都能进,战绩每天清零":" the public room — anyone can enter, the table resets daily")),console.log(chalk.gray(" ▸ ")+chalk.bold.green("room <CODE>")+chalk.gray(s?" 进朋友开的房(4 个字母)":" enter a friend's room (4-letter code)")),console.log(chalk.gray(" ▸ ")+chalk.bold.green(s?"room new [名字]":"room new [label]")+chalk.gray(s?" 开一个新房,把房号发给朋友":" open a new room and hand out its code")),"back"}let _=null;if(f){const o=await b(a,s);if(null===o)return"back";const e=await c("create",t,{label:w,nick:o});if(!e.ok||!e.data)return console.log(chalk.yellow(" "+p(e.code,e.message))),"back";_=e.data,console.log(chalk.green(" ✓ ")+chalk.white(s?"房间开好了,房号 ":"Room created — the code is ")+chalk.bold.cyan(_.room)+chalk.white(s?",告诉朋友敲 room "+_.room:`. Friends type room ${_.room}`))}else{const o=await c("status",t,{room:h});if(o.ok&&o.data)_=o.data;else{if("not_member"!==o.code)return console.log(chalk.yellow(" "+p(o.code,o.message))),"back";{const o=await c("join",t,{room:h,probe:!0}),e=o.data?.label||("OPEN"===h?s?"公共房":"Open room":h);console.log(chalk.white(` ${s?"进入":"Entering"} `)+chalk.bold.cyan(h)+chalk.gray(` ${e} · ${o.data?.members??"?"} ${s?"人":"members"}`));for(let o=0;o<4&&!_;o++){const o=await b(a,s);if(null===o)return"back";const e=await c("join",t,{room:h,nick:o});e.ok&&e.data?_=e.data:console.log(chalk.yellow(" "+p(e.code,e.message)))}if(!_)return"back"}}}const P=_.room,j=chalk.bold.magenta(`icoa room ${P}> `);for(m(_),u(P);;){const r=await a(j);if(null===r)return"back";const l=r.trim(),i=l.toLowerCase();if(d.has(i))return"back";if("menu"===i||"home"===i)return"menu";if(""===i||"who"===i||"board"===i||"table"===i||"r"===i||"refresh"===i){const o=await c("status",t,{room:P});o.ok&&o.data?m(o.data):console.log(chalk.yellow(" "+p(o.code,o.message)));continue}if("help"===i||"?"===i){u(P);continue}if("log"===i||"matches"===i||"history"===i){const o=await c("matches",t,{room:P,limit:20,all:"history"===i});if(o.ok&&o.data){o.data.matches.length||console.log(chalk.gray(s?" 今天还没有对局。":" No matches today yet."));for(const e of o.data.matches)console.log(" "+$(e))}else console.log(chalk.yellow(" "+p(o.code,o.message)));continue}if("replay"===i||"replay last"===i){await n()||console.log(chalk.gray(s?" 还没有回放 —— 先 vs 打一场。":" No replay yet — challenge someone first (vs)."));continue}const g=/^(?:up|upload|submit|上传)(?:\s+(.+))?$/i.exec(l);if(g){const a=(g[1]??"").trim()||DEFAULT_PVP_BOT;if(!o(a)){console.log(chalk.yellow(` ${s?"找不到":"Not found"}: ${a}`)),console.log(chalk.gray(s?" 默认发 ~/.icoa/battleai/bot.py(battle 界面里 edit 的那个文件);也可以 up <路径>。":" Default is ~/.icoa/battleai/bot.py (the file `edit` opens in battle); or up <path>."));continue}let n="";try{n=e(a,"utf8")}catch{console.log(chalk.yellow(` ${s?"读不了":"Could not read"}: ${a}`));continue}const r=await c("upload",t,{room:P,code:n},3e4);if(!r.ok||!r.data){console.log(chalk.yellow(" "+p(r.code,r.message)));continue}r.data.unchanged?console.log(chalk.gray(s?` 和 v${r.data.version} 一字不差,没有新版本。`:` Identical to v${r.data.version} — nothing new.`)):console.log(chalk.green(" ✓ ")+chalk.white(s?`已上传为 v${r.data.version}`:`Uploaded as v${r.data.version}`)+chalk.gray(` (${a})`));continue}const b=/^(?:vs|challenge|fight|挑战|打)\s+(\S+)(?:\s+v?(\d+))?$/i.exec(l);if(b){const o=b[2]?Number(b[2]):void 0;console.log(chalk.gray(s?" ⚖ 判分机在打 6 局(3 张图 × 换席位),通常 5–30 秒,最多 3 分钟…":" ⚖ The judge is playing 6 games (3 maps × both seats) — usually 5–30 s, up to 3 min…"));const e=await c("challenge",t,{room:P,nick:b[1],version:o},2e5);if(!e.ok||!e.data){console.log(chalk.yellow(" "+p(e.code,e.message)));continue}y(e.data),m(e.data.status);continue}/^(?:vs|challenge|挑战|打)$/i.test(l)?console.log(chalk.gray(s?" 用法: vs <昵称> 或 vs <昵称> v2(打对方的第 2 版)":" Usage: vs <nick> or vs <nick> v2 (their version 2)")):(console.log(chalk.gray(s?` 不认识「${l}」。`:` Unknown: "${l}".`)),u(P))}}async function b(o,e){for(let t=0;t<4;t++){const t=await o(chalk.bold.cyan(e?" 你的昵称(2–12 个字母/数字,别用真名;back 取消): ":" Your nickname (2–12 letters/digits, not your real name; back to cancel): "));if(null===t||d.has(t.toLowerCase()))return null;if(/^[A-Za-z0-9_\-一-鿿]{2,12}$/.test(t))return t;console.log(chalk.gray(e?" 2–12 个字母、数字、_ 或 -,不能有空格。":" 2–12 letters, digits, _ or -; no spaces."))}return null}function p(o,e){const t=i();switch(o){case"wrong_course":return t?"PvP 房间只对 BattleAI(battleai-48)token 开放。":"PvP rooms are for BattleAI (battleai-48) tokens.";case"demo_not_supported":return t?"demo token 进不了 PvP 房间。":"Demo tokens cannot enter PvP rooms.";case"no_room":return t?"没有这个房号 —— 检查一下 4 个字母。":"No room with that code — check the four letters.";case"nick_taken":return t?"这个昵称在房里已经有人用了,换一个。":"That nickname is taken in this room — pick another.";case"bad_nick":return t?"昵称要 2–12 个字母/数字,不能有空格。":"Nickname: 2–12 letters/digits, no spaces.";case"no_bot":return t?"先 up 上传你的 bot。":"Upload your bot first: up";case"opp_no_bot":return e||(t?"对方还没上传 bot。":"They have no bot yet.");case"no_such_nick":return t?"房里没有这个昵称 —— 回车看名单。":"Nobody by that name here — press Enter for the table.";case"self":return t?"不能挑战自己。":"You cannot challenge yourself.";case"cooldown":return t?"每 10 秒只能发起一场。":"One challenge every 10 seconds.";case"no_act":return t?"这个文件里没有 act(u) —— 确定是你的 bot.py?":"That file has no act(u) — is it your bot.py?";case"judge_unreachable":case"judge_timeout":case"judge_rejected":case"judge_not_configured":return t?"判分机暂时不可用,一分钟后再试。":"The judge is unavailable right now — try again in a minute.";default:return e||(t?"连不上服务器。":"Could not reach the server.")}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "icoa-cli",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.636",
|
|
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",
|