icoa-cli 2.19.538 → 2.19.539
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-render.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import chalk from"chalk";import o from"string-width";import{localized as e}from"./learn-curricula.js";import{t as n}from"./learn-i18n.js";import{getConfig as t}from"./config.js";import{icoaBannerLines as r}from"./banner.js";import{renderCharts as l,detectCaps as a}from"./render-card.js";import{replyChipLabel as s}from"./learn-replies.js";function c(){return(t().language||"en").toLowerCase()}let g="normal";export function resolveLearnWidth(o){return"normal"===o.learnWidth||"wide"===o.learnWidth||"wider"===o.learnWidth||"widest"===o.learnWidth?o.learnWidth:o.learnWide?"wide":"normal"}export function setLearnWidth(o){g=o}export function learnWidthCap(o=g){return"widest"===o?160:"wider"===o?120:"wide"===o?96:64}export function learnW(){const o=process.stdout.columns||69,e=Math.max(40,Math.min(64,o-5));return"normal"===g?e:Math.max(e,Math.min(o-6,learnWidthCap()))}const i=learnW;function d(o="─"){return o.repeat(i()+2)}function y(e,n){if(o(e)<=n)return e;let t=e;for(;t.length>0&&o(t)>Math.max(1,n-1);)t=t.slice(0,-1);return t.trimEnd()+"…"}function h(o,e,n=20){const t=e>0?o/e:0,r=Math.floor(t*n),l=n-r;return`${chalk.green("█".repeat(r))+chalk.gray("░".repeat(l))} ${(100*t).toFixed(1)}%`}function u(o){return o>=30?chalk.red("🔥🔥🔥 "+o+" days"):o>=7?chalk.yellow("🔥 "+o+" days"):o>=1?chalk.gray("· "+o+" day"+(o>1?"s":"")):chalk.gray("—")}export function renderWelcome(o,e,t){const r=c(),l=e.cardsCompleted.length,a=o.totalCards,s=a-l,g=o.modules.find(o=>e.currentCard>=o.cardRange[0]&&e.currentCard<=o.cardRange[1]),p=/demo/i.test(o.id);if(console.log(),console.log(chalk.cyan(" ╭"+d("═"))),console.log(chalk.cyan(" ║")),console.log(chalk.cyan(" ║ ")+chalk.bold.white(" "+(o.name?.trim()||n("academy_title",r)))),console.log(chalk.cyan(" ║")),t)console.log(chalk.cyan(" ║ ")+chalk.white(" "+n(p?"welcome_new_demo":"welcome_new",r)));else{const o=new Date(e.lastSeenAt),t=Math.floor((Date.now()-o.getTime())/36e5),l=t<1?n("just_now",r):t<24?`${t}${n("ago_hours",r)}`:`${Math.floor(t/24)}${n("ago_days",r)}`;console.log(chalk.cyan(" ║ ")+chalk.white(` ${n("welcome_back",r)} ${l}`))}console.log(chalk.cyan(" ║"));const m=y(g?`${g.number}. ${g.name}`:"—",i()-14);console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("module",r).padEnd(11))+chalk.white(m)),console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("progress",r).padEnd(11))+h(l,a,Math.max(6,Math.min(20,i()-26-`${l}/${a}`.length)))+chalk.gray(` (${l}/${a})`)),console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("streak",r).padEnd(11))+u(e.streakDays)),s>0&&e.currentCard<=a&&console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("next_card",r).padEnd(11))+chalk.white(`#${e.currentCard} ${n("of",r)} ${a}`)),console.log(chalk.cyan(" ║")),console.log(chalk.cyan(" ╰"+d("═"))),console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────"));const b=0===l?n("continue_start",r):`${n("continue_resume",r)} ${e.currentCard}`;console.log(chalk.bold.green(" continue")+chalk.gray(" "+b)),console.log(chalk.yellow(" status")+chalk.gray(" "+n("status_full",r))),e.bookmarks.length>0&&console.log(chalk.yellow(" bookmarks")+chalk.gray(` ${e.bookmarks.length} ${n("bookmarks_desc",r)}`)),console.log(chalk.gray(" quit")+chalk.gray(" "+n("quit_desc",r))),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log()}function p(e,t){const r=c(),l=e.module,a=t.modules.find(o=>o.number===l),s=a?a.name:n("unknown_module",r),g=n("module",r).replace(":","").trim(),d=y(`${n("card",r)} ${e.number} / ${t.totalCards} · ${g} ${l} · ${s}`,i()-4);console.log(),console.log(chalk.cyan(" ╭─ ")+chalk.bold.white(d)+" "+chalk.cyan("─".repeat(Math.max(0,i()-o(d)-4))))}function m(){console.log(chalk.cyan(" ╰"+d())),console.log()}function b(o){console.log(chalk.cyan(" │ ")+chalk.white(o))}function f(){console.log(chalk.cyan(" │"))}const $=/[┌┐└┘├┤┬┴┼─│╔╗╚╝═║╠╣╦╩╬▓▒░█]/;function w(o){return/^(?: {4}|\t)/.test(o)||$.test(o)||/ {3,}/.test(o)}export function wrapMixed(e,n){const t=[];let r="",l=0,a=!1;for(const s of function(e){const n=[],t=e=>{let t="";const r=()=>{t&&(n.push({t:"atom",s:t}),t="")};for(const l of e)" "===l?(r(),n.push({t:"space"})):2===o(l)?(r(),n.push({t:"wide",s:l})):t+=l;r()},r=/`[^`]*`/g;let l,a=0;for(;null!==(l=r.exec(e));)t(e.slice(a,l.index)),n.push({t:"code",s:l[0]}),a=l.index+l[0].length;return t(e.slice(a)),n}(e)){if("space"===s.t){""!==r&&(a=!0);continue}const e=s.s,c=o("code"===s.t?e.replace(/`/g,""):e),g=a?1:0,i="atom"===s.t&&e.length<=2&&/^[.,;:!?)\]}…'"]+$/.test(e);""!==r&&!i&&l+g+c>n?(t.push(r),r=e,l=c,a=!1):(a&&(r+=" ",l+=1,a=!1),r+=e,l+=c)}return r&&t.push(r),t}const _=/\b(?:Common bug|Common mistake|Common error|Pitfall|Gotcha|Footgun)\b[::]?|\b(?:Warning|Caution)\b[::]|(?:常见错误|常见陷阱|常见误区|陷阱|注意|警告|误区)[::]/gi;function k(o,e){const n=e?chalk.bold.white:chalk.white;let t,r="",l=0;for(_.lastIndex=0;null!==(t=_.exec(o));)t.index>l&&(r+=n(o.slice(l,t.index))),r+=chalk.bold.yellow(t[0]),l=t.index+t[0].length;return l<o.length&&(r+=n(o.slice(l))),r}function x(o,e=!1){let n="",t=0;const r=/`([^`]*)`/g;let l;for(;null!==(l=r.exec(o));)l.index>t&&(n+=k(o.slice(t,l.index),e)),n+=chalk.cyan(l[1]),t=l.index+l[0].length;return t<o.length&&(n+=k(o.slice(t),e)),n}function C(o,e=!1){let n=!1;for(const t of o.split("\n"))if(/^\s*```/.test(t))n=!n;else if(n)console.log(chalk.cyan(" │ ")+chalk.cyan(` ${t}`));else if(""!==t)if(w(t))console.log(chalk.cyan(" │ ")+chalk.white(t));else for(const o of wrapMixed(t,i()-4))console.log(chalk.cyan(" │ ")+` ${x(o,e)}`);else f()}function M(o,e){const n=[];for(const t of o.split("\n")){if(""===t){n.push("");continue}if(w(t)){n.push(t);continue}let o="";for(const r of t.split(" "))(o+" "+r).trim().length>e?(n.push(o.trim()),o=r):o=(o+" "+r).trim();o&&n.push(o)}return n}let v=!1;export function setLearnAiEnabled(o){v=o}let W=new Set;export function setLearnPqsViewCards(o){W=o}let S=new Map;export function setLearnHonorRanks(o){S=o}const z=["①","②","③","④","⑤","⑥","⑦","⑧","⑨","⑩"];let j=[];export function setLearnReplies(o){j=o}let A=[];export function setLearnFaqs(o){A=o}let q=null;export function setLearnHometask(o){q=o}let P="full";export function setLearnFooterProfile(o){P=o}let E=null;export function setLearnFooterExtra(o){E=o}function L(){const o=E?.();o&&console.log(chalk.gray(" "+o))}let R=null;export function setLearnPracticeChips(o){R=o}let N=null;export function setLearnPracticeCount(o){N=o}export function renderHonorWall(o){const e=c().startsWith("zh"),{totals:n,chapters:t}=o,r=n.gold+n.silver+n.bronze,l=(o,e)=>e>0?chalk.bold.white(`${o}×${e}`):chalk.gray(`${o}×0`);if(console.log(chalk.gray(" ─────────────────────────────────────────")),console.log(chalk.bold.white(e?" 🏅 奖牌墙 ":" 🏅 Medal wall ")+l("🥇",n.gold)+chalk.gray(" · ")+l("🥈",n.silver)+chalk.gray(" · ")+l("🥉",n.bronze)+chalk.gray(e?" (永久 — 挂上墙就不会摘下)":" (permanent — once earned, never removed)")),0===r){const n=null!=o.floor?`${o.floor}+`:e?"高分":"a high score";return console.log(chalk.gray(e?` 还没有奖牌 — 单卡提问评分 ${n} 并进入该卡前三,即可永久挂墙 🥇🥈🥉`:` No medals yet — score ${n} on a card and hold its top-3 to hang one 🥇🥈🥉`)),void console.log(chalk.gray(" ─────────────────────────────────────────"))}const a=t.map(o=>{const e=`Ch${o.chapter}`,n=(o.gold>0?`🥇${o.gold}`:"")+(o.silver>0?`🥈${o.silver}`:"")+(o.bronze>0?`🥉${o.bronze}`:"");return n?chalk.white(`${e} ${n}`):chalk.gray(`${e} —`)}).join(chalk.gray(" "));console.log(" "+a);const s=t.flatMap(o=>o.cards.map(e=>({...e,chapter:o.chapter})));s.sort((o,e)=>o.rank-e.rank||o.chapter-e.chapter||o.card-e.card);for(const o of s.slice(0,24)){const n=(o.since||"").slice(0,10);console.log(chalk.white(` ${o.icon} `)+chalk.gray(`Ch${o.chapter} · `)+chalk.white(e?`第 ${o.card} 张`:`card ${o.card}`)+chalk.gray(` · ${o.score}`)+(n?chalk.gray(e?` · 始于 ${n}`:` · since ${n}`):""))}s.length>24&&console.log(chalk.gray(e?` …还有 ${s.length-24} 枚`:` …and ${s.length-24} more`)),console.log(chalk.gray(" ─────────────────────────────────────────"))}export function renderKnowledgeCard(t,r){const d=c(),y=e(t,d);p(y,r),f();const h=wrapMixed(y.title,i()-4);for(const o of h)b(chalk.bold.yellow(o));b(chalk.gray("─".repeat(Math.min(Math.max(...h.map(e=>o(e))),i()))));const u=!!(t.chart_ids&&t.chart_ids.length>0);if(u&&l(t.chart_ids.slice(0,1),r.charts,a()),y.key_point&&""!==y.key_point.trim()?(u||f(),function(o,e,n){const t=c().startsWith("zh"),r=a().cols,l="-".repeat(Math.min(i(),Math.max(24,r-6))),s=t?"要点":"KEY POINT",g=t?`第 ${e} / ${n} 张`:`Card ${e} / ${n}`;console.log(chalk.cyan(" │ ")+chalk.green(l)),console.log(chalk.cyan(" │ ")+chalk.green(`${s} · ${g}`));for(const e of wrapMixed(o,i()-4))console.log(chalk.cyan(" │ ")+chalk.bold.green(" "+e));console.log(chalk.cyan(" │ ")+chalk.green(l)),f()}(y.key_point,y.number,r.totalCards)):u||f(),y.body.filter(o=>null!=o&&""!==o.trim()).forEach((o,e)=>{const n=0===e?o.match(/^([\s\S]*?(?:[.!?](?=\s|$)|[。!?]))(\s[\s\S]*)?$/):null;if(n&&n[1].trim().length<=180){C(n[1],!0);const o=n[2]?.trimStart();o&&C(o,!1)}else C(o,!1);f()}),y.icoaConnection){b(chalk.magenta(" "+n("icoa_connection",d))),b(chalk.gray(" "+"─".repeat(20)));for(const o of wrapMixed(y.icoaConnection,i()-4))b(" "+chalk.magenta(o));f()}if(t.check){const o=d.startsWith("zh"),e=t._zh?.checkStatement??t._zh?.check?.statement,n=o?e??t.check.statement:t.check.statement;for(const e of wrapMixed(o?"请回答 (输 y 或 n):":"Quick comprehension check (type y or n):",i()-8))b(chalk.cyan(" 🤔 "+e));b(chalk.gray(" "+"─".repeat(20)));for(const o of wrapMixed(n,i()-4))b(" "+chalk.white(o));f()}m(),function(e,n){const t=c().startsWith("zh"),r=a().cols,l="-".repeat(Math.min(i(),Math.max(24,r-6))),d=chalk.gray(" ");if("minimal"===P){const o=R?R(e.number):null;console.log(chalk.gray(" "+l)),console.log(chalk.gray(" "+(t?`第 ${e.number} / ${n.totalCards} 张`:`Card ${e.number} / ${n.totalCards}`))+(o?chalk.gray(t?" · 本卡练习 ":" · practice ")+o:""));const r=[];if(e.check?(r.push(chalk.bold.green("[y]")+chalk.gray(t?" 是":" yes")),r.push(chalk.bold.green("[n]")+chalk.gray(t?" 否":" no"))):r.push(chalk.bold.green("[ok]")+chalk.gray(t?" 下一张":" next")),o){const e=Math.max(1,(o.match(/\[\d\]/g)??[]).length),n=Array.from({length:e},(o,e)=>`[${e+1}]`).join("");r.push(chalk.bold.cyan(n)+chalk.gray(t?" 练习":" practice"))}return r.push(chalk.bold.cyan("[b]")+chalk.gray(t?" 上一张":" back")),r.push(chalk.bold.yellow("[e]")+chalk.gray(t?" 求助":" help")),r.push(chalk.gray("[quit]")+(t?chalk.gray(" 退出"):"")),console.log(" "+r.join(d)),L(),void console.log()}const y=[];e.check?(y.push(chalk.bold.green("[y]")+chalk.gray(t?" 是":" yes")),y.push(chalk.bold.green("[n]")+chalk.gray(t?" 否":" no"))):y.push(chalk.bold.green("[ok]")+chalk.gray(t?" 继续":" next")),v&&(y.push(chalk.bold.magenta("[/ai]")+chalk.gray(t?" 🐼 熊猫导师":" 🐼 Panda tutor")),y.push(chalk.bold.magenta("[/submit]")+chalk.gray(t?" 提问评分":" prompt score")));const h=S.get(e.number);var u;y.push(chalk.bold.magenta(h?`[/honors ${u=h,z[u-1]??`#${u}`}]`:"[/honors]")+chalk.gray(t?" 排行":" board")),"normal"===g?y.push(chalk.bold.cyan("[wide]")+chalk.gray(t?" 宽屏":" widen")):("wide"===g?y.push(chalk.bold.cyan("[wider]")+chalk.gray(t?" 更宽":" wider")):"wider"===g?(y.push(chalk.bold.cyan("[widest]")+chalk.gray(t?" 最宽":" widest")),y.push(chalk.bold.cyan("[wide]")+chalk.gray(t?" 回宽屏":" back to wide"))):y.push(chalk.bold.cyan("[wider]")+chalk.gray(t?" 回 wider":" back to wider")),y.push(chalk.bold.cyan("[normal]")+chalk.gray(t?" 标准":" standard")));const p=s(j,A,e.number,t),m=p.startsWith("💬");if(y.push((m?chalk.bold.yellow("[r]"):chalk.gray("[r]"))+(m?chalk.bold.white(` ${p}`):chalk.gray(` ${p}`))),y.push(chalk.bold.yellow("[e]")+chalk.gray(t?" 提问或报告":" ask or report")),q){const o=q,e=`${o.done}/${o.total}`,n=o.completedAt?chalk.bold.green:chalk.bold.cyan;y.push(n("[task]")+chalk.gray(t?` 本周 ${e}`:` week ${e}`))}y.push(chalk.bold.cyan("[b]")+chalk.gray(t?" 上一张":" back")),y.push(chalk.bold.cyan("[card N]")+chalk.gray(t?" 跳转":" jump")),y.push(chalk.gray("[reload]")+(t?chalk.gray(" 刷新"):"")),y.push(chalk.gray("[quit]")+(t?chalk.gray(" 退出"):""));const b=o(l);console.log(chalk.gray(" "+l)),console.log(chalk.gray(" "+(t?`第 ${e.number} / ${n.totalCards} 张`:`Card ${e.number} / ${n.totalCards}`)));let f="",$=0;for(const e of y){const n=o(e);f&&$+2+n>b?(console.log(" "+f),f=e,$=n):(f=f?f+d+e:e,$=f===e?n:$+2+n)}f&&console.log(" "+f),console.log(" "+chalk.magenta("✍ ")+chalk.magenta("[/py]")+chalk.gray(t?" Python 草稿本":" Python scratchpad")+d+chalk.magenta("[/pylist]")+chalk.gray(t?" 我的草稿":" my files")),console.log(chalk.gray(" "+l));const w=[t?"e = 就这张卡提问,或报告问题":"e = ask about this card, or report a problem",t?"更多: bookmark / unbookmark · status · lang zh/en · link":"more: bookmark / unbookmark · status · lang zh/en · link"];for(const o of w)for(const e of wrapMixed(o,b))console.log(chalk.gray(" "+e));L(),console.log()}(t,r)}export function renderCheckFeedback(o,e,n,t=!1){const r=c().startsWith("zh");if(console.log(),n)console.log(chalk.green(" ✓ ")+chalk.white(r?"答对了。":"Correct."));else if(console.log(chalk.yellow(" ✗ ")+chalk.white(r?"记下了,继续。":"Noted — moving on.")),t){const e="y"===o.check?.answer?r?"是":"Yes":r?"否":"No";console.log(chalk.gray(" "+(r?"正确答案: ":"Answer: ")+e+". "+(r?"回看上面那段。":"Re-read the paragraph above.")))}const l=r?o._zh?.solution??o.solution:o.solution;if(l&&l.length>0){console.log(),console.log(chalk.cyan(" 📝 "+(r?"解答:":"Worked solution:")));for(const o of l){for(const e of wrapMixed(o,i()-4))console.log(chalk.white(" "+e));console.log()}}console.log()}function F(o){return[chalk.white(" "+(o?"编著:Charlie Zhu":"Created & edited by Charlie Zhu")),chalk.gray(" "+(o?"ICOA 2026 创始人 · 课程总架构师":"Founder & Chief Curriculum Architect · ICOA 2026"))]}export function renderPhaseComplete(o,e,n,t,l,a){const s=c().startsWith("zh"),[g,d]=n.cardRange,y=e.checkResults||{};let h=0,u=0;for(let o=g;o<=d;o++){const e=y[String(o)];e&&(h++,e.correct&&u++)}const p="-".repeat(48);console.log();for(const o of r(" "))console.log(o);console.log(),console.log(chalk.bold.yellow(" "+p)),console.log(chalk.bold.yellow(" "+(s?`阶段 ${n.number} 完成`:`Phase ${n.number} complete`))+chalk.gray(" · ")+chalk.white(n.name));const m=h>0&&u===h?chalk.bold.green:chalk.bold.white;console.log(chalk.gray(" "+(s?"理解检查得分: ":"comprehension score: "))+m(`${u}/${h}`)+chalk.gray(0===h?s?" (本阶段未作答 y/n)":" (no y/n answered)":""));const b=String(d).length;let f=!1,$=0,w=0,_=0,k=0;for(let e=g;e<=d;e++){const n=o.cards.find(o=>o.number===e);if(!n)continue;const t=n,r=t.title??t.badge??"",l=(s?t._zh?.title??t._zh?.badge??r:r)||"",a=null!=n.check,c=y[String(e)];let g;g=c?c.correct?chalk.green("✓"):chalk.red("✗"):a?chalk.gray("○"):chalk.gray("·");const d=N?N(e):null;d&&(f=!0);const h=d?(d.solved>=d.total?chalk.green:d.solved>0?chalk.yellow:chalk.gray)(` ⚔${d.solved}/${d.total}`):"";d&&($++,d.solved>=d.total&&w++,_+=d.solved,k+=d.total);const u=wrapMixed(l,i()-10-b-(d?6:0)),p=u[0]+(u.length>1?"…":"");console.log(chalk.gray(` ${String(e).padStart(b)} `)+g+h+chalk.white(" "+p))}if(console.log(chalk.gray(s?" ✓ 答对 · ✗ 答错 · ○ 未作答 · 无 y/n 的卡不计分":" ✓ correct · ✗ wrong · ○ unanswered · cards without a y/n are unscored")),f&&console.log(chalk.bold.cyan(" ⚔ "+(s?"卡片练习: ":"practice: "))+(w>=$?chalk.bold.green:chalk.bold.white)(`${w}/${$}`)+chalk.gray(s?` 卡全完成 · ${_}/${k} 题 AC · 行内 ⚔已过/共(绿 完成 · 黄 部分 · 灰 未碰)`:` cards complete · ${_}/${k} problems AC · ⚔solved/total per row (green done · yellow partial · gray untouched)`)),l){const o=o=>"green"===o?chalk.bold.green:"blue"===o?chalk.bold.cyan:"yellow"===o?chalk.bold.yellow:chalk.bold.red;console.log(chalk.bold.magenta(" ⭐ "+(s?"提问得分 (best): ":"Prompt scores (best): "))+(0===l.length?chalk.gray(s?"本阶段尚未提问 — 用 /ai 研究,再 /submit 评分":"none this phase — research with /ai, then /submit"):l.map(e=>chalk.gray((s?"卡":"#")+e.card+" ")+o(e.tier)(String(e.score))).join(chalk.gray(" · "))))}if(a&&!a.configured){const o=d-g+1>12;console.log(chalk.gray(o?s?" 🔒 本阶段通关标准制作中 — 很快更新(360 层第二阶段标准设计中)":" 🔒 Pass criteria for this phase are in production — coming soon (360-tier second-stage standard in design)":s?" 🔒 本阶段通关标准制作中 — 很快更新(标准范式:3 场练习赛 + 3 卡研究)":" 🔒 Pass criteria for this phase are in production — coming soon (standard: 3 arenas + 3 research cards)"))}if(a?.configured&&a.contest){const o=a.contest;if(o.slots&&o.slots.length>0)for(const e of o.slots){const o=chalk.bold.cyan(` ⚔ ${s?"练习赛":"arena"} ${n.number}-${e.slot}: `);e.passed?console.log(o+chalk.bold.green(`${e.best_ac}/${e.n} AC ✅`)):0===e.attempts?console.log(o+chalk.white(s?`${e.n} 题 · 过 ${e.need} 题 — `:`${e.n} problems · AC ${e.need} — `)+chalk.bold.green(`contest ${e.slot}`)):console.log(o+chalk.yellow(s?`最好 ${e.best_ac}/${e.n}(需 ${e.need})· 已试 ${e.attempts} 次 — `:`best ${e.best_ac}/${e.n} (need ${e.need}) · ${e.attempts} attempt(s) — `)+chalk.bold.green(`contest ${e.slot}`))}else{const e=chalk.bold.cyan(" ⚖ "+(s?"判分赛: ":"Contest: "));o.passed?console.log(e+chalk.bold.green(`${o.best_ac}/${o.n} AC ✅ `+(s?"已过关":"passed"))):0===o.attempts?console.log(e+chalk.white(s?`${o.n} 题 · 过 ${o.need} 题解锁 — 输入 `:`${o.n} problems · AC ${o.need} to pass — type `)+chalk.bold.green("contest")+chalk.white(s?" 开始":" to start")):console.log(e+chalk.yellow(s?`最好 ${o.best_ac}/${o.n} AC(需 ${o.need})· 已试 ${o.attempts} 次 — 输入 `:`best ${o.best_ac}/${o.n} AC (need ${o.need}) · ${o.attempts} attempt(s) — type `)+chalk.bold.green("contest")+chalk.yellow(s?" 再战":" to retry"))}}t&&console.log(chalk.gray(" "+(s?"下一阶段: ":"next: "))+chalk.bold.cyan(s?`阶段 ${t.number}`:`Phase ${t.number}`)+chalk.gray(" · ")+chalk.white(t.name)),console.log(chalk.bold.yellow(" "+p));for(const o of F(s))console.log(o)}export function renderCurriculumComplete(o,e){const n=c().startsWith("zh"),t=e.checkResults||{},l="-".repeat(48);let a=0,s=0;console.log();for(const o of r(" "))console.log(o);console.log(),console.log(chalk.bold.green(" "+l)),console.log(chalk.bold.green(" 🏆 "+(n?`${o.name} — 全部完成!`:`${o.name} — complete!`))),console.log(chalk.bold.green(" "+l));for(const e of o.modules){const[o,r]=e.cardRange;let l=0,c=0;for(let e=o;e<=r;e++){const o=t[String(e)];o&&(l++,o.correct&&c++)}a+=l,s+=c;const g=l>0&&c===l?chalk.green:chalk.white;console.log(chalk.gray(" "+(n?`阶段 ${e.number}`:`Phase ${e.number}`).padEnd(8))+g(`${c}/${l}`.padEnd(7))+chalk.gray(e.name))}console.log(chalk.bold.green(" "+l)),console.log(chalk.bold.green(" "+(n?"总分 / overall: ":"Overall: "))+chalk.bold.white(`${s}/${a}`)),console.log(chalk.bold.green(" "+l));for(const o of F(n))console.log(o);console.log()}export function renderMCQCard(o,t){const r=c(),l=e(o,r);p(l,t),f(),b(chalk.bold.yellow("🎯 "+l.title)),b(chalk.gray("─".repeat(Math.min(l.title.length+4,i())))),f();for(const o of M(l.question,i()-4))b(" "+o);f();for(const o of["A","B","C","D"])b(chalk.cyan(` ${o}.`)+" "+chalk.white(l.options[o]));f(),m(),console.log(chalk.gray(" "+(r.startsWith("zh")?"输入 ":"Type "))+chalk.bold.green("A")+chalk.gray(" / ")+chalk.bold.green("B")+chalk.gray(" / ")+chalk.bold.green("C")+chalk.gray(" / ")+chalk.bold.green("D")+chalk.gray(" "+n("type_to_answer",r))),console.log(chalk.gray(" ")+chalk.bold.cyan("back")+chalk.gray(r.startsWith("zh")?" 上一张 · ":" previous card · ")+chalk.bold.cyan("card N")+chalk.gray(r.startsWith("zh")?" 跳转":" jump")),console.log()}export function renderMCQFeedback(o,t,r,l){const a=c(),s=e(o,a);console.log(),r?console.log(" "+chalk.bold.green(n("correct",a)+" ")+chalk.gray(`${n("one_point",a)} · ${t} = ${s.options[t]}`)):console.log(" "+chalk.bold.red(n("not_quite",a)+" ")+chalk.gray(`${n("you_chose",a)} ${t}; ${n("answer_is",a)} ${s.answer}.`)),console.log(),console.log(chalk.gray(" "+n("explanation",a)));for(const o of M(s.explanation,i()-4))console.log(chalk.gray(" "+o));const g=Object.values(l.mcqResults),d=g.filter(o=>o.correct).length;console.log(),console.log(chalk.gray(" "+n("mcq_accuracy_so_far",a)+" ")+chalk.white(`${d}/${g.length}`)),console.log(),r||(console.log(chalk.gray(" "+n("press_ok_continue",a)+" ")+chalk.bold.green("ok")+chalk.gray(" "+n("to_continue",a))),console.log())}export function renderPracticalCard(o,t){const r=c(),l=e(o,r);p(l,t),f(),b(chalk.bold.yellow("🛠 "+l.title)),b(chalk.gray("─".repeat(Math.min(l.title.length+4,i())))),f();for(const o of M(l.task,i()-4))b(" "+o);if(l.starterCode){f(),b(chalk.gray(" "+n("starter_code",r))),f();for(const o of l.starterCode.split("\n"))b(" "+chalk.cyan(o))}f(),m(),console.log(chalk.gray(" "+n("try_in_sandbox",r)+" ")+chalk.bold.cyan("!python3")+chalk.gray(" "+n("drops_into_python",r))),console.log(chalk.gray(" "+n("when_done",r))),console.log(chalk.gray(" ")+chalk.bold.green("done")+chalk.gray(" "+n("done_desc",r))),console.log(chalk.gray(" ")+chalk.bold.yellow("skip")+chalk.gray(" "+n("skip_desc",r))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log()}export function renderPracticalSuccess(o){const t=c(),r=e(o,t);console.log(),console.log(" "+chalk.bold.green(n("practical_recorded",t))),console.log(),console.log(chalk.gray(" "+n("reference_answer",t)));for(const o of M(r.successHint,i()-4))console.log(chalk.gray(" "+o));console.log(),console.log(chalk.gray(" "+n("press_ok_continue",t)+" ")+chalk.bold.green("ok")+chalk.gray(" "+n("to_continue",t))),console.log()}export function renderSimDemoCard(o,t){const r=c(),l=e(o,r);p(l,t),f(),b(chalk.bold.yellow("🎬 "+l.title)),f();for(const o of M(l.description,i()-4))b(" "+o);f(),b(chalk.gray(" "+n("sim_requires",r))),f(),m(),console.log(chalk.gray(" ")+chalk.bold.cyan("sim")+chalk.gray(" "+n("sim_launch_desc",r))),console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(" "+n("continue_to_next",r))),console.log(chalk.gray(" bookmark "+n("bookmark_desc",r))),console.log(chalk.gray(" back "+n("back_desc",r))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+n("quit_desc",r))),console.log()}export function renderArenaTaskCard(o,n){const t=c(),r=t.startsWith("zh"),l=e(o,t);p(l,n),f(),b(chalk.bold.cyan("🏟 "+l.title)),b(chalk.gray(" "+l.origin+" · "+l.domain+" · "+l.metric)),f();for(const o of l.statement){for(const e of M(o,i()-4))b(" "+e);f()}b(chalk.bold.green(r?" 核心要点 — baseline → 解法的关键变化":" CORE DELTA — baseline → solution"));for(const o of l.core_delta)for(const e of M("• "+o,i()-6))b(" "+chalk.white(e));f(),b(chalk.gray((r?" 提交格式: ":" Submission: ")+l.submission_format)),l.hints&&b(chalk.gray(r?" 本题有 5 级提示 (a–e),进入 arena 后逐级解锁。":" 5 progressive hints (a–e) unlock inside the arena.")),f(),m(),console.log(chalk.gray(" ")+chalk.bold.cyan("arena "+l.task_id)+chalk.gray(r?" 动手做这道题(下载 / 提示 / 提交 / 榜单)":" open the arena (download / hints / submit / board)")),console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(r?" 继续下一张":" continue to next")),console.log(chalk.gray(" back "+(r?"上一张":"previous"))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+(r?"退出":"exit"))),console.log()}export function renderComingSoonCard(o,n){const t=c(),r=t.startsWith("zh"),l=e(o,t);p(l,n),f(),b(chalk.bold.yellow("🔜 "+l.title)),f();const a=l.note||(r?"这道竞技场题目正在编写中,敬请期待。":"This arena task is coming soon.");for(const o of M(a,i()-4))b(" "+chalk.gray(o));f(),m(),console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(r?" 继续":" continue")),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+(r?"退出":"exit"))),console.log()}export function renderMilestone(o,t){const r=c(),l=e(o,r),a=o.number===t.totalCards;console.log(),console.log(chalk.bold.yellow(" ╭"+d("═"))),console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ║ ")+chalk.white(" "+n("milestone_header",r))),console.log(chalk.bold.yellow(" ║"));const s=` ${l.badge} ${l.emoji}`;console.log(chalk.bold.yellow(" ║ ")+chalk.bold.green(s)),console.log(chalk.bold.yellow(" ║ ")+chalk.gray(" ─".repeat(Math.max(1,Math.floor(l.badge.length/2+2))))),console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ║ ")+" "+chalk.gray(n("in_wild_corresponds",r)));for(const o of M(l.realWorldLevel,i()-4))console.log(chalk.bold.yellow(" ║ ")+" "+chalk.white(o));console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ║ ")+" "+chalk.gray(n("whats_next",r)));for(const o of M(l.unlockedNext,i()-4))console.log(chalk.bold.yellow(" ║ ")+" "+chalk.white(o));console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ╰"+d("═"))),console.log(),a?(console.log(chalk.gray(" "+n("demo_complete",r))),console.log(),console.log(chalk.gray(" "+n("unlock_full",r)+" ")+chalk.white(n("curriculum_name",r))+chalk.gray(",")),console.log(chalk.gray(" "+n("contact_team_leader",r)+" ")+chalk.bold.yellow("EA")+chalk.gray(" "+n("learn_token",r))),console.log(chalk.gray(" "+n("or_email",r)+" ")+chalk.cyan("australia@icoa2026.au")+chalk.gray(" "+n("for_partnership",r))),console.log(),console.log(chalk.gray(" "+n("type_quit",r)+" ")+chalk.bold.green("quit")+chalk.gray(" "+n("to_exit",r)+" ")+chalk.bold.green("status")+chalk.gray(" "+n("for_dashboard",r)))):(console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(" "+n("continue_to_next",r))),console.log(chalk.gray(" status "+n("status_full",r))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+n("quit_desc",r)))),console.log()}export function renderStatus(e,t,r={}){const l=c(),a=l.startsWith("zh"),s=t.cardsCompleted.length,g=e.totalCards,d=t.checkResults||{},p=r.gate??null,$=!!r.gated,w=r.focus??"current",_=r.posForSlot??(o=>4===o?10:4*o),k=t.currentCard,x=e.modules.find(o=>k>=o.cardRange[0]&&k<=o.cardRange[1]),C=(e,n)=>e+" ".repeat(Math.max(0,n-o((o=>o.replace(/\x1b\[[0-9;]*m/g,""))(e))));console.log();const M=`${e.name} — ${a?"状态":"Status"}`;console.log(chalk.cyan(" ╭─ ")+chalk.bold.white(M)+" "+chalk.cyan("─".repeat(Math.max(4,i()-2-o(M))))),f(),b(" "+chalk.gray(n("total_progress",l)+" ")+h(s,g)+chalk.gray(` (${s}/${g})`)+chalk.gray(" "+n("streak",l)+" ")+u(t.streakDays)),f();const v=o=>a?`阶段 ${o}`:`Phase ${o}`,W=Math.max(10,Math.min(28,i()-54));for(const o of e.modules){const[n,r]=o.cardRange,l=r-n+1,s=t.cardsCompleted.filter(o=>o>=n&&o<=r).length,c=$&&!!p&&o.number>p.unlocked_through_phase,g=p?.phases.find(e=>e.phase===o.number);let h=0,u=0,m=0;const f=[],M=[];let S=0,z=0,j=0,A=0;const q=[];for(let o=n;o<=r;o++){const n=e.cards.find(e=>e.number===o);if(null!=n?.check){h++;const e=d[String(o)];e?(u++,e.correct?m++:M.push(o)):f.push(o)}const t=N?N(o):null;t&&(S++,j+=t.solved,A+=t.total,t.solved>=t.total?z++:q.push(`${o}:${t.solved}/${t.total}`))}const P=g?.configured?g.contest?.slots??[]:[],E=o=>o.passed?chalk.green("✅"):o.attempts>0?chalk.yellow("❌"):chalk.gray("⬜"),L=s>=l&&(0===h||m===h)&&(0===S||z===S)&&(0===P.length||P.every(o=>o.passed))&&(!g?.research||g.research.passed),R=s>0||u>0||j>0||P.some(o=>o.attempts>0),F=c?chalk.gray("🔒"):L?chalk.green("✅"):o.number===x?.number?chalk.bold.cyan("▶ "):R?chalk.yellow("▶ "):chalk.gray("⬜"),D=y(o.name,W),O=[];if(O.push((s>=l?chalk.green:chalk.white)(`${s}/${l}`)+chalk.gray(a?"卡":"c")),h>0&&O.push(chalk.gray("✓")+(m===h?chalk.green:chalk.white)(`${m}/${h}`)),S>0&&O.push(chalk.gray("⚔")+(z===S?chalk.green:chalk.white)(`${j}/${A}`)),P.length>0&&O.push(chalk.gray(a?"赛":"arena ")+P.map(E).join("")),g?.research&&O.push(chalk.gray("⭐")+(g.research.passed?chalk.green:chalk.white)(`${g.research.good_cards}/${g.research.need_cards}`)),b(" "+F+" "+chalk.white(C(v(o.number),a?5:8))+chalk.gray(C(D,W+1))+O.join(chalk.gray(" · "))),c||"all"!==w&&w!==o.number&&("current"!==w||o.number!==x?.number)){if(!c&&R&&!L){const e=[],t=P.filter(o=>!o.passed).map(e=>(e.attempts>0?chalk.yellow:chalk.gray)(`${o.number}-${e.slot}@${a?"卡":"card "}${n+_(e.slot)-1}`));t.length&&e.push(chalk.gray(a?"赛 ":"arena ")+t.join(chalk.gray(" · ")));const r=(o,e)=>o.slice(0,8).join(e)+(o.length>8?chalk.gray(" +"+(o.length-8)):"");q.length&&e.push(chalk.gray("⚔ ")+chalk.white(r(q," "))),M.length&&e.push(chalk.red("✗ ")+chalk.white(r(M.map(String),","))),f.length&&e.push(chalk.gray("○ ")+chalk.white(r(f.map(String),","))),g?.research&&!g.research.passed&&e.push(chalk.gray(`⭐ ${g.research.good_cards}/${g.research.need_cards}`)),e.forEach((o,e)=>b(chalk.gray(0===e?a?" 待办: ":" todo: ":" ")+o))}}else{const t=String(r).length;for(let l=n;l<=r;l++){const r=e.cards.find(o=>o.number===l);if(!r)continue;const s=r,c=s.title??s.badge??"",g=(a?s._zh?.title??s._zh?.badge??c:c)||"",y=null!=r.check,h=d[String(l)],u=h?h.correct?chalk.green("✓"):chalk.red("✗"):y?chalk.gray("○"):chalk.gray("·"),p=N?N(l):null,m=p?(p.solved>=p.total?chalk.green:p.solved>0?chalk.yellow:chalk.gray)(`⚔${p.solved}/${p.total}`):" ",f=l===k?chalk.bold.cyan("▶"):" ",$=wrapMixed(g,Math.max(16,i()-14-t)),w=$[0]+($.length>1?"…":"");b(` ${f} `+chalk.gray(String(l).padStart(t))+" "+u+" "+C(m,5)+" "+chalk.white(w));const x=P.find(o=>n+_(o.slot)-1===l);if(x){const e=chalk.gray(` ${" ".repeat(t)} ⚔ ${a?"练习赛":"arena"} ${o.number}-${x.slot}: `);x.passed?b(e+chalk.bold.green(`${x.best_ac}/${x.n} AC ✅`)):0===x.attempts?b(e+chalk.gray("⬜ ")+chalk.white(a?`未开始 · ${x.n} 题 · 过 ${x.need} 题 → `:`not started · ${x.n} problems · AC ${x.need} → `)+chalk.bold.green(`contest ${x.slot}`)):b(e+chalk.yellow(a?`❌ 最好 ${x.best_ac}/${x.n}(需 ${x.need})· 已试 ${x.attempts} 次 → `:`❌ best ${x.best_ac}/${x.n} (need ${x.need}) · ${x.attempts} attempt(s) → `)+chalk.bold.green(`contest ${x.slot}`))}}g?.research&&!g.research.passed&&b(chalk.gray(a?` ⭐ 研究: ${g.research.good_cards}/${g.research.need_cards} 卡达 ${g.research.min_score} 分 — /ai 研究后 /submit`:` ⭐ research: ${g.research.good_cards}/${g.research.need_cards} cards at ${g.research.min_score}+ — /ai then /submit`)),g&&!g.configured&&b(chalk.gray(a?" 🔒 本阶段通关标准制作中 — 很快更新":" 🔒 pass criteria for this phase in production — coming soon"))}}f(),b(chalk.gray(a?" ✓ 答对 ✗ 答错 ○ 未答 · ⚔ 练习 已过/共 · 赛 ✅ 过 ❌ 试过 ⬜ 未碰 · ⭐ 研究":" ✓ right ✗ wrong ○ unanswered · ⚔ practice solved/total · ⭐ research")),b(chalk.gray(a?" 展开某阶段: ":" arena ✅ passed ❌ tried ⬜ untouched · expand: ")+chalk.bold.green("status all")+chalk.gray(" / ")+chalk.bold.green("status N")),t.achievements.length>0&&b(" "+chalk.gray(n("achievements",l)+" ")+t.achievements.map(o=>chalk.bold.yellow("★ ")+chalk.white(o)).join(chalk.gray(" · "))),f(),m()}
|
|
1
|
+
import chalk from"chalk";import o from"string-width";import{localized as e}from"./learn-curricula.js";import{t as n}from"./learn-i18n.js";import{getConfig as t}from"./config.js";import{icoaBannerLines as r}from"./banner.js";import{renderCharts as l,detectCaps as a}from"./render-card.js";import{replyChipLabel as s}from"./learn-replies.js";function c(){return(t().language||"en").toLowerCase()}let g="normal";export function resolveLearnWidth(o){return"normal"===o.learnWidth||"wide"===o.learnWidth||"wider"===o.learnWidth||"widest"===o.learnWidth?o.learnWidth:o.learnWide?"wide":"normal"}export function setLearnWidth(o){g=o}export function learnWidthCap(o=g){return"widest"===o?160:"wider"===o?120:"wide"===o?96:64}export function learnW(){const o=process.stdout.columns||69,e=Math.max(40,Math.min(64,o-5));return"normal"===g?e:Math.max(e,Math.min(o-6,learnWidthCap()))}const i=learnW;function d(o="─"){return o.repeat(i()+2)}function y(e,n){if(o(e)<=n)return e;let t=e;for(;t.length>0&&o(t)>Math.max(1,n-1);)t=t.slice(0,-1);return t.trimEnd()+"…"}function h(o,e,n=20){const t=e>0?o/e:0,r=Math.floor(t*n),l=n-r;return`${chalk.green("█".repeat(r))+chalk.gray("░".repeat(l))} ${(100*t).toFixed(1)}%`}function u(o){return o>=30?chalk.red("🔥🔥🔥 "+o+" days"):o>=7?chalk.yellow("🔥 "+o+" days"):o>=1?chalk.gray("· "+o+" day"+(o>1?"s":"")):chalk.gray("—")}export function renderWelcome(o,e,t){const r=c(),l=e.cardsCompleted.length,a=o.totalCards,s=a-l,g=o.modules.find(o=>e.currentCard>=o.cardRange[0]&&e.currentCard<=o.cardRange[1]),p=/demo/i.test(o.id);if(console.log(),console.log(chalk.cyan(" ╭"+d("═"))),console.log(chalk.cyan(" ║")),console.log(chalk.cyan(" ║ ")+chalk.bold.white(" "+(o.name?.trim()||n("academy_title",r)))),console.log(chalk.cyan(" ║")),t)console.log(chalk.cyan(" ║ ")+chalk.white(" "+n(p?"welcome_new_demo":"welcome_new",r)));else{const o=new Date(e.lastSeenAt),t=Math.floor((Date.now()-o.getTime())/36e5),l=t<1?n("just_now",r):t<24?`${t}${n("ago_hours",r)}`:`${Math.floor(t/24)}${n("ago_days",r)}`;console.log(chalk.cyan(" ║ ")+chalk.white(` ${n("welcome_back",r)} ${l}`))}console.log(chalk.cyan(" ║"));const m=y(g?`${g.number}. ${g.name}`:"—",i()-14);console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("module",r).padEnd(11))+chalk.white(m)),console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("progress",r).padEnd(11))+h(l,a,Math.max(6,Math.min(20,i()-26-`${l}/${a}`.length)))+chalk.gray(` (${l}/${a})`)),console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("streak",r).padEnd(11))+u(e.streakDays)),s>0&&e.currentCard<=a&&console.log(chalk.cyan(" ║ ")+" "+chalk.gray(n("next_card",r).padEnd(11))+chalk.white(`#${e.currentCard} ${n("of",r)} ${a}`)),console.log(chalk.cyan(" ║")),console.log(chalk.cyan(" ╰"+d("═"))),console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────"));const b=0===l?n("continue_start",r):`${n("continue_resume",r)} ${e.currentCard}`;console.log(chalk.bold.green(" continue")+chalk.gray(" "+b)),console.log(chalk.yellow(" status")+chalk.gray(" "+n("status_full",r))),e.bookmarks.length>0&&console.log(chalk.yellow(" bookmarks")+chalk.gray(` ${e.bookmarks.length} ${n("bookmarks_desc",r)}`)),console.log(chalk.gray(" quit")+chalk.gray(" "+n("quit_desc",r))),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log()}function p(e,t){const r=c(),l=e.module,a=t.modules.find(o=>o.number===l),s=a?a.name:n("unknown_module",r),g=n("module",r).replace(":","").trim(),d=y(`${n("card",r)} ${e.number} / ${t.totalCards} · ${g} ${l} · ${s}`,i()-4);console.log(),console.log(chalk.cyan(" ╭─ ")+chalk.bold.white(d)+" "+chalk.cyan("─".repeat(Math.max(0,i()-o(d)-4))))}function m(){console.log(chalk.cyan(" ╰"+d())),console.log()}function b(o){console.log(chalk.cyan(" │ ")+chalk.white(o))}function f(){console.log(chalk.cyan(" │"))}const $=/[┌┐└┘├┤┬┴┼─│╔╗╚╝═║╠╣╦╩╬▓▒░█]/;function w(o){return/^(?: {4}|\t)/.test(o)||$.test(o)||/ {3,}/.test(o)}export function wrapMixed(e,n){const t=[];let r="",l=0,a=!1;for(const s of function(e){const n=[],t=e=>{let t="";const r=()=>{t&&(n.push({t:"atom",s:t}),t="")};for(const l of e)" "===l?(r(),n.push({t:"space"})):2===o(l)?(r(),n.push({t:"wide",s:l})):t+=l;r()},r=/`[^`]*`/g;let l,a=0;for(;null!==(l=r.exec(e));)t(e.slice(a,l.index)),n.push({t:"code",s:l[0]}),a=l.index+l[0].length;return t(e.slice(a)),n}(e)){if("space"===s.t){""!==r&&(a=!0);continue}const e=s.s,c=o("code"===s.t?e.replace(/`/g,""):e),g=a?1:0,i="atom"===s.t&&e.length<=2&&/^[.,;:!?)\]}…'"]+$/.test(e);""!==r&&!i&&l+g+c>n?(t.push(r),r=e,l=c,a=!1):(a&&(r+=" ",l+=1,a=!1),r+=e,l+=c)}return r&&t.push(r),t}const _=/\b(?:Common bug|Common mistake|Common error|Pitfall|Gotcha|Footgun)\b[::]?|\b(?:Warning|Caution)\b[::]|(?:常见错误|常见陷阱|常见误区|陷阱|注意|警告|误区)[::]/gi;function k(o,e){const n=e?chalk.bold.white:chalk.white;let t,r="",l=0;for(_.lastIndex=0;null!==(t=_.exec(o));)t.index>l&&(r+=n(o.slice(l,t.index))),r+=chalk.bold.yellow(t[0]),l=t.index+t[0].length;return l<o.length&&(r+=n(o.slice(l))),r}function x(o,e=!1){let n="",t=0;const r=/`([^`]*)`/g;let l;for(;null!==(l=r.exec(o));)l.index>t&&(n+=k(o.slice(t,l.index),e)),n+=chalk.cyan(l[1]),t=l.index+l[0].length;return t<o.length&&(n+=k(o.slice(t),e)),n}function C(o,e=!1){let n=!1;for(const t of o.split("\n"))if(/^\s*```/.test(t))n=!n;else if(n)console.log(chalk.cyan(" │ ")+chalk.cyan(` ${t}`));else if(""!==t)if(w(t))console.log(chalk.cyan(" │ ")+chalk.white(t));else for(const o of wrapMixed(t,i()-4))console.log(chalk.cyan(" │ ")+` ${x(o,e)}`);else f()}function M(o,e){const n=[];for(const t of o.split("\n")){if(""===t){n.push("");continue}if(w(t)){n.push(t);continue}let o="";for(const r of t.split(" "))(o+" "+r).trim().length>e?(n.push(o.trim()),o=r):o=(o+" "+r).trim();o&&n.push(o)}return n}let v=!1;export function setLearnAiEnabled(o){v=o}let W=new Set;export function setLearnPqsViewCards(o){W=o}let S=new Map;export function setLearnHonorRanks(o){S=o}const j=["①","②","③","④","⑤","⑥","⑦","⑧","⑨","⑩"];let z=[];export function setLearnReplies(o){z=o}let A=[];export function setLearnFaqs(o){A=o}let R=null;export function setLearnHometask(o){R=o}let q="full";export function setLearnFooterProfile(o){q=o}let P=null;export function setLearnFooterExtra(o){P=o}function E(){const o=P?.();o&&console.log(chalk.gray(" "+o))}let L=null;export function setLearnPracticeChips(o){L=o}let N=null;export function setLearnPracticeCount(o){N=o}export function renderHonorWall(o){const e=c().startsWith("zh"),{totals:n,chapters:t}=o,r=n.gold+n.silver+n.bronze,l=(o,e)=>e>0?chalk.bold.white(`${o}×${e}`):chalk.gray(`${o}×0`);if(console.log(chalk.gray(" ─────────────────────────────────────────")),console.log(chalk.bold.white(e?" 🏅 奖牌墙 ":" 🏅 Medal wall ")+l("🥇",n.gold)+chalk.gray(" · ")+l("🥈",n.silver)+chalk.gray(" · ")+l("🥉",n.bronze)+chalk.gray(e?" (永久 — 挂上墙就不会摘下)":" (permanent — once earned, never removed)")),0===r){const n=null!=o.floor?`${o.floor}+`:e?"高分":"a high score";return console.log(chalk.gray(e?` 还没有奖牌 — 单卡提问评分 ${n} 并进入该卡前三,即可永久挂墙 🥇🥈🥉`:` No medals yet — score ${n} on a card and hold its top-3 to hang one 🥇🥈🥉`)),void console.log(chalk.gray(" ─────────────────────────────────────────"))}const a=t.map(o=>{const e=`Ch${o.chapter}`,n=(o.gold>0?`🥇${o.gold}`:"")+(o.silver>0?`🥈${o.silver}`:"")+(o.bronze>0?`🥉${o.bronze}`:"");return n?chalk.white(`${e} ${n}`):chalk.gray(`${e} —`)}).join(chalk.gray(" "));console.log(" "+a);const s=t.flatMap(o=>o.cards.map(e=>({...e,chapter:o.chapter})));s.sort((o,e)=>o.rank-e.rank||o.chapter-e.chapter||o.card-e.card);for(const o of s.slice(0,24)){const n=(o.since||"").slice(0,10);console.log(chalk.white(` ${o.icon} `)+chalk.gray(`Ch${o.chapter} · `)+chalk.white(e?`第 ${o.card} 张`:`card ${o.card}`)+chalk.gray(` · ${o.score}`)+(n?chalk.gray(e?` · 始于 ${n}`:` · since ${n}`):""))}s.length>24&&console.log(chalk.gray(e?` …还有 ${s.length-24} 枚`:` …and ${s.length-24} more`)),console.log(chalk.gray(" ─────────────────────────────────────────"))}export function renderKnowledgeCard(t,r){const d=c(),y=e(t,d);p(y,r),f();const h=wrapMixed(y.title,i()-4);for(const o of h)b(chalk.bold.yellow(o));b(chalk.gray("─".repeat(Math.min(Math.max(...h.map(e=>o(e))),i()))));const u=!!(t.chart_ids&&t.chart_ids.length>0);if(u&&l(t.chart_ids.slice(0,1),r.charts,a()),y.key_point&&""!==y.key_point.trim()?(u||f(),function(o,e,n){const t=c().startsWith("zh"),r=a().cols,l="-".repeat(Math.min(i(),Math.max(24,r-6))),s=t?"要点":"KEY POINT",g=t?`第 ${e} / ${n} 张`:`Card ${e} / ${n}`;console.log(chalk.cyan(" │ ")+chalk.green(l)),console.log(chalk.cyan(" │ ")+chalk.green(`${s} · ${g}`));for(const e of wrapMixed(o,i()-4))console.log(chalk.cyan(" │ ")+chalk.bold.green(" "+e));console.log(chalk.cyan(" │ ")+chalk.green(l)),f()}(y.key_point,y.number,r.totalCards)):u||f(),y.body.filter(o=>null!=o&&""!==o.trim()).forEach((o,e)=>{const n=0===e?o.match(/^([\s\S]*?(?:[.!?](?=\s|$)|[。!?]))(\s[\s\S]*)?$/):null;if(n&&n[1].trim().length<=180){C(n[1],!0);const o=n[2]?.trimStart();o&&C(o,!1)}else C(o,!1);f()}),y.icoaConnection){b(chalk.magenta(" "+n("icoa_connection",d))),b(chalk.gray(" "+"─".repeat(20)));for(const o of wrapMixed(y.icoaConnection,i()-4))b(" "+chalk.magenta(o));f()}if(t.check){const o=d.startsWith("zh"),e=t._zh?.checkStatement??t._zh?.check?.statement,n=o?e??t.check.statement:t.check.statement;for(const e of wrapMixed(o?"请回答 (输 y 或 n):":"Quick comprehension check (type y or n):",i()-8))b(chalk.cyan(" 🤔 "+e));b(chalk.gray(" "+"─".repeat(20)));for(const o of wrapMixed(n,i()-4))b(" "+chalk.white(o));f()}m(),function(e,n){const t=c().startsWith("zh"),r=a().cols,l="-".repeat(Math.min(i(),Math.max(24,r-6))),d=chalk.gray(" ");if("minimal"===q){const o=L?L(e.number):null;console.log(chalk.gray(" "+l)),console.log(chalk.gray(" "+(t?`第 ${e.number} / ${n.totalCards} 张`:`Card ${e.number} / ${n.totalCards}`))+(o?chalk.gray(t?" · 本卡练习 ":" · practice ")+o:""));const r=[];if(e.check?(r.push(chalk.bold.green("[y]")+chalk.gray(t?" 是":" yes")),r.push(chalk.bold.green("[n]")+chalk.gray(t?" 否":" no"))):r.push(chalk.bold.green("[ok]")+chalk.gray(t?" 下一张":" next")),o){const e=Math.max(1,(o.match(/\[\d\]/g)??[]).length),n=Array.from({length:e},(o,e)=>`[${e+1}]`).join("");r.push(chalk.bold.cyan(n)+chalk.gray(t?" 练习":" practice"))}return r.push(chalk.bold.cyan("[b]")+chalk.gray(t?" 上一张":" back")),r.push(chalk.bold.yellow("[e]")+chalk.gray(t?" 求助":" help")),r.push(chalk.gray("[quit]")+(t?chalk.gray(" 退出"):"")),console.log(" "+r.join(d)),E(),void console.log()}const y=[];e.check?(y.push(chalk.bold.green("[y]")+chalk.gray(t?" 是":" yes")),y.push(chalk.bold.green("[n]")+chalk.gray(t?" 否":" no"))):y.push(chalk.bold.green("[ok]")+chalk.gray(t?" 继续":" next")),v&&(y.push(chalk.bold.magenta("[/ai]")+chalk.gray(t?" 🐼 熊猫导师":" 🐼 Panda tutor")),y.push(chalk.bold.magenta("[/submit]")+chalk.gray(t?" 提问评分":" prompt score")));const h=S.get(e.number);var u;y.push(chalk.bold.magenta(h?`[/honors ${u=h,j[u-1]??`#${u}`}]`:"[/honors]")+chalk.gray(t?" 排行":" board")),"normal"===g?y.push(chalk.bold.cyan("[wide]")+chalk.gray(t?" 宽屏":" widen")):("wide"===g?y.push(chalk.bold.cyan("[wider]")+chalk.gray(t?" 更宽":" wider")):"wider"===g?(y.push(chalk.bold.cyan("[widest]")+chalk.gray(t?" 最宽":" widest")),y.push(chalk.bold.cyan("[wide]")+chalk.gray(t?" 回宽屏":" back to wide"))):y.push(chalk.bold.cyan("[wider]")+chalk.gray(t?" 回 wider":" back to wider")),y.push(chalk.bold.cyan("[normal]")+chalk.gray(t?" 标准":" standard")));const p=s(z,A,e.number,t),m=p.startsWith("💬");if(y.push((m?chalk.bold.yellow("[r]"):chalk.gray("[r]"))+(m?chalk.bold.white(` ${p}`):chalk.gray(` ${p}`))),y.push(chalk.bold.yellow("[e]")+chalk.gray(t?" 提问或报告":" ask or report")),R){const o=R,e=`${o.done}/${o.total}`,n=o.completedAt?chalk.bold.green:chalk.bold.cyan;y.push(n("[task]")+chalk.gray(t?` 本周 ${e}`:` week ${e}`))}y.push(chalk.bold.cyan("[b]")+chalk.gray(t?" 上一张":" back")),y.push(chalk.bold.cyan("[card N]")+chalk.gray(t?" 跳转":" jump")),y.push(chalk.gray("[reload]")+(t?chalk.gray(" 刷新"):"")),y.push(chalk.gray("[quit]")+(t?chalk.gray(" 退出"):""));const b=o(l);console.log(chalk.gray(" "+l)),console.log(chalk.gray(" "+(t?`第 ${e.number} / ${n.totalCards} 张`:`Card ${e.number} / ${n.totalCards}`)));let f="",$=0;for(const e of y){const n=o(e);f&&$+2+n>b?(console.log(" "+f),f=e,$=n):(f=f?f+d+e:e,$=f===e?n:$+2+n)}f&&console.log(" "+f),console.log(" "+chalk.magenta("✍ ")+chalk.magenta("[/py]")+chalk.gray(t?" Python 草稿本":" Python scratchpad")+d+chalk.magenta("[/pylist]")+chalk.gray(t?" 我的草稿":" my files")),console.log(chalk.gray(" "+l));const w=[t?"e = 就这张卡提问,或报告问题":"e = ask about this card, or report a problem",t?"更多: bookmark / unbookmark · status · lang zh/en · link":"more: bookmark / unbookmark · status · lang zh/en · link"];for(const o of w)for(const e of wrapMixed(o,b))console.log(chalk.gray(" "+e));E(),console.log()}(t,r)}export function renderCheckFeedback(o,e,n,t=!1){const r=c().startsWith("zh");if(console.log(),n)console.log(chalk.green(" ✓ ")+chalk.white(r?"答对了。":"Correct."));else if(console.log(chalk.yellow(" ✗ ")+chalk.white(r?"记下了,继续。":"Noted — moving on.")),t){const e="y"===o.check?.answer?r?"是":"Yes":r?"否":"No";console.log(chalk.gray(" "+(r?"正确答案: ":"Answer: ")+e+". "+(r?"回看上面那段。":"Re-read the paragraph above.")))}const l=r?o._zh?.solution??o.solution:o.solution;if(l&&l.length>0){console.log(),console.log(chalk.cyan(" 📝 "+(r?"解答:":"Worked solution:")));for(const o of l){for(const e of wrapMixed(o,i()-4))console.log(chalk.white(" "+e));console.log()}}console.log()}function F(o){return[chalk.white(" "+(o?"编著:Charlie Zhu":"Created & edited by Charlie Zhu")),chalk.gray(" "+(o?"ICOA 2026 创始人 · 课程总架构师":"Founder & Chief Curriculum Architect · ICOA 2026"))]}export function renderPhaseComplete(o,e,n,t,l,a){const s=c().startsWith("zh"),[g,d]=n.cardRange,y=e.checkResults||{};let h=0,u=0;for(let o=g;o<=d;o++){const e=y[String(o)];e&&(h++,e.correct&&u++)}const p="-".repeat(48);console.log();for(const o of r(" "))console.log(o);console.log(),console.log(chalk.bold.yellow(" "+p)),console.log(chalk.bold.yellow(" "+(s?`阶段 ${n.number} 完成`:`Phase ${n.number} complete`))+chalk.gray(" · ")+chalk.white(n.name));const m=h>0&&u===h?chalk.bold.green:chalk.bold.white;console.log(chalk.gray(" "+(s?"理解检查得分: ":"comprehension score: "))+m(`${u}/${h}`)+chalk.gray(0===h?s?" (本阶段未作答 y/n)":" (no y/n answered)":""));const b=String(d).length;let f=!1,$=0,w=0,_=0,k=0;for(let e=g;e<=d;e++){const n=o.cards.find(o=>o.number===e);if(!n)continue;const t=n,r=t.title??t.badge??"",l=(s?t._zh?.title??t._zh?.badge??r:r)||"",a=null!=n.check,c=y[String(e)];let g;g=c?c.correct?chalk.green("✓"):chalk.red("✗"):a?chalk.gray("○"):chalk.gray("·");const d=N?N(e):null;d&&(f=!0);const h=d?(d.solved>=d.total?chalk.green:d.solved>0?chalk.yellow:chalk.gray)(` ⚔${d.solved}/${d.total}`):"";d&&($++,d.solved>=d.total&&w++,_+=d.solved,k+=d.total);const u=wrapMixed(l,i()-10-b-(d?6:0)),p=u[0]+(u.length>1?"…":"");console.log(chalk.gray(` ${String(e).padStart(b)} `)+g+h+chalk.white(" "+p))}if(console.log(chalk.gray(s?" ✓ 答对 · ✗ 答错 · ○ 未作答 · 无 y/n 的卡不计分":" ✓ correct · ✗ wrong · ○ unanswered · cards without a y/n are unscored")),f&&console.log(chalk.bold.cyan(" ⚔ "+(s?"卡片练习: ":"practice: "))+(w>=$?chalk.bold.green:chalk.bold.white)(`${w}/${$}`)+chalk.gray(s?` 卡全完成 · ${_}/${k} 题 AC · 行内 ⚔已过/共(绿 完成 · 黄 部分 · 灰 未碰)`:` cards complete · ${_}/${k} problems AC · ⚔solved/total per row (green done · yellow partial · gray untouched)`)),l){const o=o=>"green"===o?chalk.bold.green:"blue"===o?chalk.bold.cyan:"yellow"===o?chalk.bold.yellow:chalk.bold.red;console.log(chalk.bold.magenta(" ⭐ "+(s?"提问得分 (best): ":"Prompt scores (best): "))+(0===l.length?chalk.gray(s?"本阶段尚未提问 — 用 /ai 研究,再 /submit 评分":"none this phase — research with /ai, then /submit"):l.map(e=>chalk.gray((s?"卡":"#")+e.card+" ")+o(e.tier)(String(e.score))).join(chalk.gray(" · "))))}if(a&&!a.configured){const o=d-g+1>12;console.log(chalk.gray(o?s?" 🔒 本阶段通关标准制作中 — 很快更新(360 层第二阶段标准设计中)":" 🔒 Pass criteria for this phase are in production — coming soon (360-tier second-stage standard in design)":s?" 🔒 本阶段通关标准制作中 — 很快更新(标准范式:3 场练习赛 + 3 卡研究)":" 🔒 Pass criteria for this phase are in production — coming soon (standard: 3 arenas + 3 research cards)"))}if(a?.configured&&a.contest){const o=a.contest;if(o.slots&&o.slots.length>0)for(const e of o.slots){const o=chalk.bold.cyan(` ⚔ ${s?"练习赛":"arena"} ${n.number}-${e.slot}: `);e.passed?console.log(o+chalk.bold.green(`${e.best_ac}/${e.n} AC ✅`)):0===e.attempts?console.log(o+chalk.white(s?`${e.n} 题 · 过 ${e.need} 题 — `:`${e.n} problems · AC ${e.need} — `)+chalk.bold.green(`contest ${e.slot}`)):console.log(o+chalk.yellow(s?`最好 ${e.best_ac}/${e.n}(需 ${e.need})· 已试 ${e.attempts} 次 — `:`best ${e.best_ac}/${e.n} (need ${e.need}) · ${e.attempts} attempt(s) — `)+chalk.bold.green(`contest ${e.slot}`))}else{const e=chalk.bold.cyan(" ⚖ "+(s?"判分赛: ":"Contest: "));o.passed?console.log(e+chalk.bold.green(`${o.best_ac}/${o.n} AC ✅ `+(s?"已过关":"passed"))):0===o.attempts?console.log(e+chalk.white(s?`${o.n} 题 · 过 ${o.need} 题解锁 — 输入 `:`${o.n} problems · AC ${o.need} to pass — type `)+chalk.bold.green("contest")+chalk.white(s?" 开始":" to start")):console.log(e+chalk.yellow(s?`最好 ${o.best_ac}/${o.n} AC(需 ${o.need})· 已试 ${o.attempts} 次 — 输入 `:`best ${o.best_ac}/${o.n} AC (need ${o.need}) · ${o.attempts} attempt(s) — type `)+chalk.bold.green("contest")+chalk.yellow(s?" 再战":" to retry"))}}t&&console.log(chalk.gray(" "+(s?"下一阶段: ":"next: "))+chalk.bold.cyan(s?`阶段 ${t.number}`:`Phase ${t.number}`)+chalk.gray(" · ")+chalk.white(t.name)),console.log(chalk.bold.yellow(" "+p));for(const o of F(s))console.log(o)}export function renderCurriculumComplete(o,e){const n=c().startsWith("zh"),t=e.checkResults||{},l="-".repeat(48);let a=0,s=0;console.log();for(const o of r(" "))console.log(o);console.log(),console.log(chalk.bold.green(" "+l)),console.log(chalk.bold.green(" 🏆 "+(n?`${o.name} — 全部完成!`:`${o.name} — complete!`))),console.log(chalk.bold.green(" "+l));for(const e of o.modules){const[o,r]=e.cardRange;let l=0,c=0;for(let e=o;e<=r;e++){const o=t[String(e)];o&&(l++,o.correct&&c++)}a+=l,s+=c;const g=l>0&&c===l?chalk.green:chalk.white;console.log(chalk.gray(" "+(n?`阶段 ${e.number}`:`Phase ${e.number}`).padEnd(8))+g(`${c}/${l}`.padEnd(7))+chalk.gray(e.name))}console.log(chalk.bold.green(" "+l)),console.log(chalk.bold.green(" "+(n?"总分 / overall: ":"Overall: "))+chalk.bold.white(`${s}/${a}`)),console.log(chalk.bold.green(" "+l));for(const o of F(n))console.log(o);console.log()}export function renderMCQCard(o,t){const r=c(),l=e(o,r);p(l,t),f(),b(chalk.bold.yellow("🎯 "+l.title)),b(chalk.gray("─".repeat(Math.min(l.title.length+4,i())))),f();for(const o of M(l.question,i()-4))b(" "+o);f();for(const o of["A","B","C","D"])b(chalk.cyan(` ${o}.`)+" "+chalk.white(l.options[o]));f(),m(),console.log(chalk.gray(" "+(r.startsWith("zh")?"输入 ":"Type "))+chalk.bold.green("A")+chalk.gray(" / ")+chalk.bold.green("B")+chalk.gray(" / ")+chalk.bold.green("C")+chalk.gray(" / ")+chalk.bold.green("D")+chalk.gray(" "+n("type_to_answer",r))),console.log(chalk.gray(" ")+chalk.bold.cyan("back")+chalk.gray(r.startsWith("zh")?" 上一张 · ":" previous card · ")+chalk.bold.cyan("card N")+chalk.gray(r.startsWith("zh")?" 跳转":" jump")),console.log()}export function renderMCQFeedback(o,t,r,l){const a=c(),s=e(o,a);console.log(),r?console.log(" "+chalk.bold.green(n("correct",a)+" ")+chalk.gray(`${n("one_point",a)} · ${t} = ${s.options[t]}`)):console.log(" "+chalk.bold.red(n("not_quite",a)+" ")+chalk.gray(`${n("you_chose",a)} ${t}; ${n("answer_is",a)} ${s.answer}.`)),console.log(),console.log(chalk.gray(" "+n("explanation",a)));for(const o of M(s.explanation,i()-4))console.log(chalk.gray(" "+o));const g=Object.values(l.mcqResults),d=g.filter(o=>o.correct).length;console.log(),console.log(chalk.gray(" "+n("mcq_accuracy_so_far",a)+" ")+chalk.white(`${d}/${g.length}`)),console.log(),r||(console.log(chalk.gray(" "+n("press_ok_continue",a)+" ")+chalk.bold.green("ok")+chalk.gray(" "+n("to_continue",a))),console.log())}export function renderPracticalCard(o,t){const r=c(),l=e(o,r);p(l,t),f(),b(chalk.bold.yellow("🛠 "+l.title)),b(chalk.gray("─".repeat(Math.min(l.title.length+4,i())))),f();for(const o of M(l.task,i()-4))b(" "+o);if(l.starterCode){f(),b(chalk.gray(" "+n("starter_code",r))),f();for(const o of l.starterCode.split("\n"))b(" "+chalk.cyan(o))}f(),m(),console.log(chalk.gray(" "+n("try_in_sandbox",r)+" ")+chalk.bold.cyan("!python3")+chalk.gray(" "+n("drops_into_python",r))),console.log(chalk.gray(" "+n("when_done",r))),console.log(chalk.gray(" ")+chalk.bold.green("done")+chalk.gray(" "+n("done_desc",r))),console.log(chalk.gray(" ")+chalk.bold.yellow("skip")+chalk.gray(" "+n("skip_desc",r))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log()}export function renderPracticalSuccess(o){const t=c(),r=e(o,t);console.log(),console.log(" "+chalk.bold.green(n("practical_recorded",t))),console.log(),console.log(chalk.gray(" "+n("reference_answer",t)));for(const o of M(r.successHint,i()-4))console.log(chalk.gray(" "+o));console.log(),console.log(chalk.gray(" "+n("press_ok_continue",t)+" ")+chalk.bold.green("ok")+chalk.gray(" "+n("to_continue",t))),console.log()}export function renderSimDemoCard(o,t){const r=c(),l=e(o,r);p(l,t),f(),b(chalk.bold.yellow("🎬 "+l.title)),f();for(const o of M(l.description,i()-4))b(" "+o);f(),b(chalk.gray(" "+n("sim_requires",r))),f(),m(),console.log(chalk.gray(" ")+chalk.bold.cyan("sim")+chalk.gray(" "+n("sim_launch_desc",r))),console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(" "+n("continue_to_next",r))),console.log(chalk.gray(" bookmark "+n("bookmark_desc",r))),console.log(chalk.gray(" back "+n("back_desc",r))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+n("quit_desc",r))),console.log()}export function renderArenaTaskCard(o,n){const t=c(),r=t.startsWith("zh"),l=e(o,t);p(l,n),f(),b(chalk.bold.cyan("🏟 "+l.title)),b(chalk.gray(" "+l.origin+" · "+l.domain+" · "+l.metric)),f();for(const o of l.statement){for(const e of M(o,i()-4))b(" "+e);f()}b(chalk.bold.green(r?" 核心要点 — baseline → 解法的关键变化":" CORE DELTA — baseline → solution"));for(const o of l.core_delta)for(const e of M("• "+o,i()-6))b(" "+chalk.white(e));f(),b(chalk.gray((r?" 提交格式: ":" Submission: ")+l.submission_format)),l.hints&&b(chalk.gray(r?" 本题有 5 级提示 (a–e),进入 arena 后逐级解锁。":" 5 progressive hints (a–e) unlock inside the arena.")),f(),m(),console.log(chalk.gray(" ")+chalk.bold.cyan("arena "+l.task_id)+chalk.gray(r?" 动手做这道题(下载 / 提示 / 提交 / 榜单)":" open the arena (download / hints / submit / board)")),console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(r?" 继续下一张":" continue to next")),console.log(chalk.gray(" back "+(r?"上一张":"previous"))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+(r?"退出":"exit"))),console.log()}export function renderComingSoonCard(o,n){const t=c(),r=t.startsWith("zh"),l=e(o,t);p(l,n),f(),b(chalk.bold.yellow("🔜 "+l.title)),f();const a=l.note||(r?"这道竞技场题目正在编写中,敬请期待。":"This arena task is coming soon.");for(const o of M(a,i()-4))b(" "+chalk.gray(o));f(),m(),console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(r?" 继续":" continue")),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+(r?"退出":"exit"))),console.log()}export function renderMilestone(o,t){const r=c(),l=e(o,r),a=o.number===t.totalCards;console.log(),console.log(chalk.bold.yellow(" ╭"+d("═"))),console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ║ ")+chalk.white(" "+n("milestone_header",r))),console.log(chalk.bold.yellow(" ║"));const s=` ${l.badge} ${l.emoji}`;console.log(chalk.bold.yellow(" ║ ")+chalk.bold.green(s)),console.log(chalk.bold.yellow(" ║ ")+chalk.gray(" ─".repeat(Math.max(1,Math.floor(l.badge.length/2+2))))),console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ║ ")+" "+chalk.gray(n("in_wild_corresponds",r)));for(const o of M(l.realWorldLevel,i()-4))console.log(chalk.bold.yellow(" ║ ")+" "+chalk.white(o));console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ║ ")+" "+chalk.gray(n("whats_next",r)));for(const o of M(l.unlockedNext,i()-4))console.log(chalk.bold.yellow(" ║ ")+" "+chalk.white(o));console.log(chalk.bold.yellow(" ║")),console.log(chalk.bold.yellow(" ╰"+d("═"))),console.log(),a?(console.log(chalk.gray(" "+n("demo_complete",r))),console.log(),console.log(chalk.gray(" "+n("unlock_full",r)+" ")+chalk.white(n("curriculum_name",r))+chalk.gray(",")),console.log(chalk.gray(" "+n("contact_team_leader",r)+" ")+chalk.bold.yellow("EA")+chalk.gray(" "+n("learn_token",r))),console.log(chalk.gray(" "+n("or_email",r)+" ")+chalk.cyan("australia@icoa2026.au")+chalk.gray(" "+n("for_partnership",r))),console.log(),console.log(chalk.gray(" "+n("type_quit",r)+" ")+chalk.bold.green("quit")+chalk.gray(" "+n("to_exit",r)+" ")+chalk.bold.green("status")+chalk.gray(" "+n("for_dashboard",r)))):(console.log(chalk.gray(" ")+chalk.bold.green("ok")+chalk.gray(" / ")+chalk.bold.green("next")+chalk.gray(" "+n("continue_to_next",r))),console.log(chalk.gray(" status "+n("status_full",r))),console.log(chalk.gray(" back previous card")),console.log(chalk.gray(" card N jump to a card by number")),console.log(chalk.gray(" quit "+n("quit_desc",r)))),console.log()}export function renderStatus(e,t,r={}){const l=c(),a=l.startsWith("zh"),s=t.cardsCompleted.length,g=e.totalCards,d=t.checkResults||{},p=r.gate??null,$=!!r.gated,w=r.focus??"current",_=r.posForSlot??(o=>4===o?10:4*o),k=t.currentCard,x=e.modules.find(o=>k>=o.cardRange[0]&&k<=o.cardRange[1]),C=(e,n)=>e+" ".repeat(Math.max(0,n-o((o=>o.replace(/\x1b\[[0-9;]*m/g,""))(e))));console.log();const M=`${e.name} — ${a?"状态":"Status"}`;console.log(chalk.cyan(" ╭─ ")+chalk.bold.white(M)+" "+chalk.cyan("─".repeat(Math.max(4,i()-2-o(M))))),f(),b(" "+chalk.gray(n("total_progress",l)+" ")+h(s,g)+chalk.gray(` (${s}/${g})`)+chalk.gray(" "+n("streak",l)+" ")+u(t.streakDays));{let o=0,n=0,t=0,l=0,s=0,c=0,g=!1;for(const r of e.modules){for(let a=r.cardRange[0];a<=r.cardRange[1];a++){const r=N?N(a):null;r&&(o++,r.solved>=r.total&&n++);const s=e.cards.find(o=>o.number===a);null!=s?.check&&(t++,d[String(a)]?.correct&&l++)}const a=p?.phases.find(o=>o.phase===r.number);if(a?.configured)for(const o of a.contest?.slots??[])s++,o.passed&&c++;a?.research&&(g=!0)}const i=(o,e)=>(o>=e?chalk.green:chalk.white)(`${o}/${e}`),y=[];o&&y.push(chalk.gray(a?"⚔ 练习卡 ":"⚔ practice cards ")+i(n,o)),s&&y.push(chalk.gray(a?"赛场 ":"arena ")+i(c,s)),t&&y.push(chalk.gray(a?"✓ 自测 ":"✓ checks ")+i(l,t)),y.length&&b(" "+y.join(chalk.gray(" "))),r._anyResearch=g}f();const v=o=>a?`阶段 ${o}`:`Phase ${o}`,W=Math.max(10,Math.min(28,i()-54));for(const o of e.modules){const[n,r]=o.cardRange,l=r-n+1,s=t.cardsCompleted.filter(o=>o>=n&&o<=r).length,c=$&&!!p&&o.number>p.unlocked_through_phase,g=p?.phases.find(e=>e.phase===o.number);let h=0,u=0,m=0;const f=[],M=[];let S=0,j=0,z=0;const A=[];for(let o=n;o<=r;o++){const n=e.cards.find(e=>e.number===o);if(null!=n?.check){h++;const e=d[String(o)];e?(u++,e.correct?m++:M.push(o)):f.push(o)}const t=N?N(o):null;t&&(S++,z+=t.solved,t.solved>=t.total?j++:A.push(`${o}:${t.solved}/${t.total}`))}const R=g?.configured?g.contest?.slots??[]:[],q=o=>o.passed?chalk.green("✅"):o.attempts>0?chalk.yellow("❌"):chalk.gray("⬜"),P=s>=l&&(0===h||m===h)&&(0===S||j===S)&&(0===R.length||R.every(o=>o.passed))&&(!g?.research||g.research.passed),E=s>0||u>0||z>0||R.some(o=>o.attempts>0),L=c?chalk.gray("🔒"):P?chalk.green("✅"):o.number===x?.number?chalk.bold.cyan("▶ "):E?chalk.yellow("▶ "):chalk.gray("⬜"),F=y(o.name,W),D=[];if(D.push((s>=l?chalk.green:chalk.white)(`${s}/${l}`)+chalk.gray(a?"卡":"c")),h>0&&D.push(chalk.gray("✓")+(m===h?chalk.green:chalk.white)(`${m}/${h}`)),S>0&&D.push(chalk.gray("⚔")+(j===S?chalk.green:chalk.white)(`${j}/${S}`)+chalk.gray(a?"卡":"c")),R.length>0&&D.push(chalk.gray(a?"赛":"arena ")+R.map(q).join("")),g?.research&&D.push(chalk.gray("⭐")+(g.research.passed?chalk.green:chalk.white)(`${g.research.good_cards}/${g.research.need_cards}`)),b(" "+L+" "+chalk.white(C(v(o.number),a?5:8))+chalk.gray(C(F,W+1))+D.join(chalk.gray(" · "))),c||"all"!==w&&w!==o.number&&("current"!==w||o.number!==x?.number)){if(!c&&E&&!P){const e=[],t=R.filter(o=>!o.passed).map(e=>(e.attempts>0?chalk.yellow:chalk.gray)(`${o.number}-${e.slot}@${a?"卡":"card "}${n+_(e.slot)-1}`));t.length&&e.push(chalk.gray(a?"赛 ":"arena ")+t.join(chalk.gray(" · ")));const r=(o,e)=>o.slice(0,8).join(e)+(o.length>8?chalk.gray(" +"+(o.length-8)):"");A.length&&e.push(chalk.gray("⚔ ")+chalk.white(r(A," "))),M.length&&e.push(chalk.red("✗ ")+chalk.white(r(M.map(String),","))),f.length&&e.push(chalk.gray("○ ")+chalk.white(r(f.map(String),","))),g?.research&&!g.research.passed&&e.push(chalk.gray(`⭐ ${g.research.good_cards}/${g.research.need_cards}`)),e.forEach((o,e)=>b(chalk.gray(0===e?a?" 待办: ":" todo: ":" ")+o))}}else{const t=String(r).length;for(let l=n;l<=r;l++){const r=e.cards.find(o=>o.number===l);if(!r)continue;const s=r,c=s.title??s.badge??"",g=(a?s._zh?.title??s._zh?.badge??c:c)||"",y=null!=r.check,h=d[String(l)],u=h?h.correct?chalk.green("✓"):chalk.red("✗"):y?chalk.gray("○"):chalk.gray("·"),p=N?N(l):null,m=p?(p.solved>=p.total?chalk.green:p.solved>0?chalk.yellow:chalk.gray)(`⚔${p.solved}/${p.total}`):" ",f=l===k?chalk.bold.cyan("▶"):" ",$=wrapMixed(g,Math.max(16,i()-14-t)),w=$[0]+($.length>1?"…":"");b(` ${f} `+chalk.gray(String(l).padStart(t))+" "+u+" "+C(m,5)+" "+chalk.white(w));const x=R.find(o=>n+_(o.slot)-1===l);if(x){const e=chalk.gray(` ${" ".repeat(t)} ⚔ ${a?"练习赛":"arena"} ${o.number}-${x.slot}: `);x.passed?b(e+chalk.bold.green(`${x.best_ac}/${x.n} AC ✅`)):0===x.attempts?b(e+chalk.gray("⬜ ")+chalk.white(a?`未开始 · ${x.n} 题 · 过 ${x.need} 题 → `:`not started · ${x.n} problems · AC ${x.need} → `)+chalk.bold.green(`contest ${x.slot}`)):b(e+chalk.yellow(a?`❌ 最好 ${x.best_ac}/${x.n}(需 ${x.need})· 已试 ${x.attempts} 次 → `:`❌ best ${x.best_ac}/${x.n} (need ${x.need}) · ${x.attempts} attempt(s) → `)+chalk.bold.green(`contest ${x.slot}`))}}g?.research&&!g.research.passed&&b(chalk.gray(a?` ⭐ 研究: ${g.research.good_cards}/${g.research.need_cards} 卡达 ${g.research.min_score} 分 — /ai 研究后 /submit`:` ⭐ research: ${g.research.good_cards}/${g.research.need_cards} cards at ${g.research.min_score}+ — /ai then /submit`)),g&&!g.configured&&b(chalk.gray(a?" 🔒 本阶段通关标准制作中 — 很快更新":" 🔒 pass criteria for this phase in production — coming soon"))}}f(),b(chalk.gray(a?" ✓ 答对 ✗ 答错 ○ 未答 · ⚔ 练习 已过/共 · 赛 ✅ 过 ❌ 试过 ⬜ 未碰"+(r._anyResearch?" · ⭐ 研究":""):" ✓ right ✗ wrong ○ unanswered · ⚔ practice solved/total"+(r._anyResearch?" · ⭐ research":""))),b(chalk.gray(a?" 展开某阶段: ":" arena ✅ passed ❌ tried ⬜ untouched · expand: ")+chalk.bold.green("status all")+chalk.gray(" / ")+chalk.bold.green("status N")),t.achievements.length>0&&b(" "+chalk.gray(n("achievements",l)+" ")+t.achievements.map(o=>chalk.bold.yellow("★ ")+chalk.white(o)).join(chalk.gray(" · "))),f(),m()}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "icoa-cli",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.539",
|
|
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": {
|