icoa-cli 2.19.349 → 2.19.351
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/commands/ai4ctf.js +1 -1
- package/dist/commands/connect.js +1 -1
- package/dist/commands/ctf.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/index.js +1 -355
- package/dist/lib/access.js +1 -184
- package/dist/lib/arena-submit.js +1 -21
- package/dist/lib/budget.js +1 -6
- package/dist/lib/challenge-dir.js +1 -16
- package/dist/lib/comms.js +1 -212
- package/dist/lib/config.js +1 -93
- package/dist/lib/country-lang.js +1 -39
- package/dist/lib/demo-exam.js +1 -478
- package/dist/lib/demo-flags.js +1 -27
- package/dist/lib/demo-stats.js +1 -62
- package/dist/lib/demo2-progress.js +1 -102
- package/dist/lib/exam-client.js +1 -54
- package/dist/lib/exam-state.js +1 -273
- package/dist/lib/gemini.js +1 -247
- package/dist/lib/integrity-snapshot.js +1 -88
- package/dist/lib/interactive-spawn.js +1 -55
- package/dist/lib/ipynb-input.js +1 -65
- package/dist/lib/kernel-protocol.js +1 -88
- package/dist/lib/kernel.js +2 -146
- package/dist/lib/learn-curricula.js +1 -309
- package/dist/lib/learn-i18n.js +1 -184
- package/dist/lib/log-sync.js +1 -155
- package/dist/lib/logger.js +1 -49
- package/dist/lib/open-file.js +1 -55
- package/dist/lib/paper-upgrade.js +1 -119
- package/dist/lib/render-card.js +1 -112
- package/dist/lib/repl-asker.js +1 -67
- package/dist/lib/sample-runner.js +1 -227
- package/dist/lib/shell-split.js +1 -69
- package/dist/lib/sim-cooldown.js +1 -75
- package/dist/lib/theme.js +1 -119
- package/dist/lib/token-format.js +1 -74
- package/dist/lib/toolset-hash.js +1 -48
- package/dist/lib/translations-fetcher.js +1 -95
- package/dist/lib/ui.js +1 -99
- package/dist/lib/version.js +1 -24
- package/dist/postinstall.js +1 -48
- package/dist/repl.js +1 -2251
- package/dist/types/index.js +1 -63
- package/package.json +1 -1
|
@@ -1,95 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Lazy translation-pack fetcher.
|
|
3
|
-
*
|
|
4
|
-
* v2.19.197 moved per-language translation files (translations/<lang>/*.json)
|
|
5
|
-
* out of the npm package, saving ~280 KB. They live on icoa2026.au and get
|
|
6
|
-
* fetched + extracted under ~/.icoa/translations/<lang>/ on first lang switch.
|
|
7
|
-
*
|
|
8
|
-
* - English is bundled in source (no fetch needed)
|
|
9
|
-
* - All other supported langs ship as <lang>.tar.gz on icoa2026.au
|
|
10
|
-
* - Per-lang tarballs are 4–17 KB compressed; single HTTP round-trip
|
|
11
|
-
* - A `.cached` sentinel file marks completion (idempotent re-runs)
|
|
12
|
-
* - Extraction shells out to `tar -xzf` — present on macOS, Linux, WSL2
|
|
13
|
-
*/
|
|
14
|
-
import chalk from 'chalk';
|
|
15
|
-
import { spawn } from 'node:child_process';
|
|
16
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
17
|
-
import { join } from 'node:path';
|
|
18
|
-
import { getIcoaDir } from './config.js';
|
|
19
|
-
// Multi-source fallback: try each mirror in order before giving up to the
|
|
20
|
-
// on-the-fly translator. Two boxes on different IPs = real redundancy, so a
|
|
21
|
-
// single host being down (or its asset path not yet provisioned) no longer
|
|
22
|
-
// drops non-EN users to live Gemini. Same single git source builds both packs
|
|
23
|
-
// (scripts/build-translation-packs.sh --push sha256-gates them identical), so
|
|
24
|
-
// whichever mirror answers first serves byte-identical content.
|
|
25
|
-
//
|
|
26
|
-
// Hosts are the two boxes we hold SSH creds for → fully automatable publish
|
|
27
|
-
// (the retired icoa2026.au website had no SSH access, only a deploy webhook):
|
|
28
|
-
// primary = practice (public, always-on, NOT frozen, where learn already points)
|
|
29
|
-
// backup = mel/au (competition box). Safe as a backup because (1) the client
|
|
30
|
-
// only reaches it if practice is down, and (2) packs cache once (.cached) at
|
|
31
|
-
// language-switch time — BEFORE the exam — so exam-time fetch traffic ≈ 0,
|
|
32
|
-
// neutralising the single-venue-IP fail2ban risk.
|
|
33
|
-
const TRANSLATIONS_BASE_URLS = [
|
|
34
|
-
'https://practice.icoa2026.au/assets/translations',
|
|
35
|
-
'https://au.icoa2026.au/assets/translations',
|
|
36
|
-
];
|
|
37
|
-
export function getLangCacheDir(lang) {
|
|
38
|
-
return join(getIcoaDir(), 'translations', lang);
|
|
39
|
-
}
|
|
40
|
-
export function isLangCached(lang) {
|
|
41
|
-
if (lang === 'en')
|
|
42
|
-
return true;
|
|
43
|
-
const dir = getLangCacheDir(lang);
|
|
44
|
-
// RULE: the menu / UI chrome stays English-only — non-EN `ui.json` packs are
|
|
45
|
-
// intentionally NOT served from the asset host, so t() falls back to EN per key
|
|
46
|
-
// for chrome. Lazy-load (the `lang` command) only translates question + demo
|
|
47
|
-
// content. So the cache is valid on the `.cached` sentinel alone; do NOT also
|
|
48
|
-
// require ui.json here — it will never be present, which would force a full
|
|
49
|
-
// pack re-download on every boot for non-EN users.
|
|
50
|
-
return existsSync(join(dir, '.cached'));
|
|
51
|
-
}
|
|
52
|
-
export async function ensureLangCache(lang, opts = {}) {
|
|
53
|
-
if (lang === 'en')
|
|
54
|
-
return true;
|
|
55
|
-
if (isLangCached(lang))
|
|
56
|
-
return true;
|
|
57
|
-
const cacheDir = getLangCacheDir(lang);
|
|
58
|
-
mkdirSync(cacheDir, { recursive: true });
|
|
59
|
-
if (!opts.silent) {
|
|
60
|
-
console.log(chalk.gray(` Fetching ${lang} translation pack ...`));
|
|
61
|
-
}
|
|
62
|
-
// Try each mirror in order; the first that returns the tarball wins.
|
|
63
|
-
let lastErr = null;
|
|
64
|
-
for (const base of TRANSLATIONS_BASE_URLS) {
|
|
65
|
-
try {
|
|
66
|
-
const url = `${base}/${lang}.tar.gz`;
|
|
67
|
-
const res = await fetch(url);
|
|
68
|
-
if (!res.ok) {
|
|
69
|
-
lastErr = `HTTP ${res.status}`;
|
|
70
|
-
continue; // try next mirror
|
|
71
|
-
}
|
|
72
|
-
const tgzPath = join(cacheDir, `${lang}.tar.gz`);
|
|
73
|
-
writeFileSync(tgzPath, Buffer.from(await res.arrayBuffer()));
|
|
74
|
-
await new Promise((resolve, reject) => {
|
|
75
|
-
const proc = spawn('tar', ['-xzf', tgzPath, '-C', cacheDir], { stdio: 'ignore' });
|
|
76
|
-
proc.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`tar exit ${code}`))));
|
|
77
|
-
proc.on('error', reject);
|
|
78
|
-
});
|
|
79
|
-
writeFileSync(join(cacheDir, '.cached'), new Date().toISOString());
|
|
80
|
-
if (!opts.silent) {
|
|
81
|
-
console.log(chalk.green(` ✓ ${lang} translations cached at ~/.icoa/translations/${lang}/`));
|
|
82
|
-
}
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
catch (e) {
|
|
86
|
-
lastErr = e instanceof Error ? e.message : String(e);
|
|
87
|
-
// try next mirror
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// All mirrors exhausted → fall back to the on-the-fly translator.
|
|
91
|
-
if (!opts.silent) {
|
|
92
|
-
console.log(chalk.yellow(` Translation pack not available (${lastErr ?? 'all mirrors unreachable'}). The interface stays in English; per-question translations fall back to the on-the-fly translator.`));
|
|
93
|
-
}
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
1
|
+
import chalk from"chalk";import{spawn as t}from"node:child_process";import{existsSync as n,mkdirSync as r,writeFileSync as a}from"node:fs";import{join as e}from"node:path";import{getIcoaDir as o}from"./config.js";const s=["https://practice.icoa2026.au/assets/translations","https://au.icoa2026.au/assets/translations"];export function getLangCacheDir(t){return e(o(),"translations",t)}export function isLangCached(t){if("en"===t)return!0;const r=getLangCacheDir(t);return n(e(r,".cached"))}export async function ensureLangCache(n,o={}){if("en"===n)return!0;if(isLangCached(n))return!0;const i=getLangCacheDir(n);r(i,{recursive:!0}),o.silent||console.log(chalk.gray(` Fetching ${n} translation pack ...`));let c=null;for(const r of s)try{const s=`${r}/${n}.tar.gz`,l=await fetch(s);if(!l.ok){c=`HTTP ${l.status}`;continue}const f=e(i,`${n}.tar.gz`);return a(f,Buffer.from(await l.arrayBuffer())),await new Promise((n,r)=>{const a=t("tar",["-xzf",f,"-C",i],{stdio:"ignore"});a.on("close",t=>0===t?n():r(new Error(`tar exit ${t}`))),a.on("error",r)}),a(e(i,".cached"),(new Date).toISOString()),o.silent||console.log(chalk.green(` ✓ ${n} translations cached at ~/.icoa/translations/${n}/`)),!0}catch(t){c=t instanceof Error?t.message:String(t)}return o.silent||console.log(chalk.yellow(` Translation pack not available (${c??"all mirrors unreachable"}). The interface stays in English; per-question translations fall back to the on-the-fly translator.`)),!1}
|
package/dist/lib/ui.js
CHANGED
|
@@ -1,99 +1 @@
|
|
|
1
|
-
import chalk from
|
|
2
|
-
import Table from 'cli-table3';
|
|
3
|
-
import ora from 'ora';
|
|
4
|
-
import { Marked } from 'marked';
|
|
5
|
-
import { markedTerminal } from 'marked-terminal';
|
|
6
|
-
import { c } from './colors.js';
|
|
7
|
-
const marked = new Marked(markedTerminal());
|
|
8
|
-
// Wrap the message body in explicit Darcula fg (#A9B7C6). Without this,
|
|
9
|
-
// chalk.green('✓ ') emits \x1b[39m at the end and the unstyled msg falls
|
|
10
|
-
// back to the terminal's profile fg — which is black on macOS Terminal.app
|
|
11
|
-
// default, invisible on our forced #2B2B2B background.
|
|
12
|
-
export function printSuccess(msg) {
|
|
13
|
-
console.log(chalk.green('✓ ') + c.fg(msg));
|
|
14
|
-
}
|
|
15
|
-
export function printError(msg) {
|
|
16
|
-
console.log(chalk.red('✗ ') + c.fg(msg));
|
|
17
|
-
}
|
|
18
|
-
export function printWarning(msg) {
|
|
19
|
-
console.log(chalk.yellow('⚠ ') + c.fg(msg));
|
|
20
|
-
}
|
|
21
|
-
export function printInfo(msg) {
|
|
22
|
-
console.log(chalk.blue('ℹ ') + c.fg(msg));
|
|
23
|
-
}
|
|
24
|
-
export function printTable(headers, rows) {
|
|
25
|
-
const table = new Table({
|
|
26
|
-
head: headers.map((h) => chalk.cyan.bold(h)),
|
|
27
|
-
style: { head: [], border: [] },
|
|
28
|
-
});
|
|
29
|
-
for (const row of rows) {
|
|
30
|
-
table.push(row);
|
|
31
|
-
}
|
|
32
|
-
console.log(table.toString());
|
|
33
|
-
}
|
|
34
|
-
export function printMarkdown(text) {
|
|
35
|
-
const rendered = marked.parse(text);
|
|
36
|
-
if (typeof rendered === 'string') {
|
|
37
|
-
console.log(rendered);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
// In REPL mode, spinners conflict with readline — use simple log instead
|
|
41
|
-
let replMode = false;
|
|
42
|
-
export function setReplMode(enabled) {
|
|
43
|
-
replMode = enabled;
|
|
44
|
-
}
|
|
45
|
-
export function createSpinner(text) {
|
|
46
|
-
if (replMode) {
|
|
47
|
-
// Fake spinner that just logs — no terminal cursor manipulation
|
|
48
|
-
const fake = {
|
|
49
|
-
text,
|
|
50
|
-
start() {
|
|
51
|
-
console.log(chalk.cyan(` ${text}`));
|
|
52
|
-
return fake;
|
|
53
|
-
},
|
|
54
|
-
stop() {
|
|
55
|
-
return fake;
|
|
56
|
-
},
|
|
57
|
-
succeed(msg) {
|
|
58
|
-
console.log(chalk.green(` ✓ ${msg}`));
|
|
59
|
-
return fake;
|
|
60
|
-
},
|
|
61
|
-
fail(msg) {
|
|
62
|
-
console.log(chalk.red(` ✗ ${msg}`));
|
|
63
|
-
return fake;
|
|
64
|
-
},
|
|
65
|
-
info(msg) {
|
|
66
|
-
console.log(chalk.blue(` ℹ ${msg}`));
|
|
67
|
-
return fake;
|
|
68
|
-
},
|
|
69
|
-
warn(msg) {
|
|
70
|
-
console.log(chalk.yellow(` ⚠ ${msg}`));
|
|
71
|
-
return fake;
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
return fake;
|
|
75
|
-
}
|
|
76
|
-
return ora({ text, color: 'cyan' });
|
|
77
|
-
}
|
|
78
|
-
export function formatCountdown(targetDate) {
|
|
79
|
-
const now = new Date();
|
|
80
|
-
const diff = targetDate.getTime() - now.getTime();
|
|
81
|
-
if (diff <= 0)
|
|
82
|
-
return '00:00:00';
|
|
83
|
-
const hours = Math.floor(diff / (1000 * 60 * 60));
|
|
84
|
-
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
|
85
|
-
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
|
|
86
|
-
return [
|
|
87
|
-
hours.toString().padStart(2, '0'),
|
|
88
|
-
minutes.toString().padStart(2, '0'),
|
|
89
|
-
seconds.toString().padStart(2, '0'),
|
|
90
|
-
].join(':');
|
|
91
|
-
}
|
|
92
|
-
export function printHeader(title) {
|
|
93
|
-
console.log();
|
|
94
|
-
console.log(chalk.cyan.bold(` ${title}`));
|
|
95
|
-
console.log(chalk.cyan(` ${'─'.repeat(title.length + 4)}`));
|
|
96
|
-
}
|
|
97
|
-
export function printKeyValue(key, value) {
|
|
98
|
-
console.log(` ${chalk.gray(`${key}:`)} ${c.fg(value)}`);
|
|
99
|
-
}
|
|
1
|
+
import chalk from"chalk";import o from"cli-table3";import ora from"ora";import{Marked as t}from"marked";import{markedTerminal as n}from"marked-terminal";import{c as e}from"./colors.js";const r=new t(n());export function printSuccess(o){console.log(chalk.green("✓ ")+e.fg(o))}export function printError(o){console.log(chalk.red("✗ ")+e.fg(o))}export function printWarning(o){console.log(chalk.yellow("⚠ ")+e.fg(o))}export function printInfo(o){console.log(chalk.blue("ℹ ")+e.fg(o))}export function printTable(t,n){const e=new o({head:t.map(o=>chalk.cyan.bold(o)),style:{head:[],border:[]}});for(const o of n)e.push(o);console.log(e.toString())}export function printMarkdown(o){const t=r.parse(o);"string"==typeof t&&console.log(t)}let l=!1;export function setReplMode(o){l=o}export function createSpinner(o){if(l){const t={text:o,start:()=>(console.log(chalk.cyan(` ${o}`)),t),stop:()=>t,succeed:o=>(console.log(chalk.green(` ✓ ${o}`)),t),fail:o=>(console.log(chalk.red(` ✗ ${o}`)),t),info:o=>(console.log(chalk.blue(` ℹ ${o}`)),t),warn:o=>(console.log(chalk.yellow(` ⚠ ${o}`)),t)};return t}return ora({text:o,color:"cyan"})}export function formatCountdown(o){const t=new Date,n=o.getTime()-t.getTime();if(n<=0)return"00:00:00";const e=Math.floor(n/36e5),r=Math.floor(n%36e5/6e4),l=Math.floor(n%6e4/1e3);return[e.toString().padStart(2,"0"),r.toString().padStart(2,"0"),l.toString().padStart(2,"0")].join(":")}export function printHeader(o){console.log(),console.log(chalk.cyan.bold(` ${o}`)),console.log(chalk.cyan(` ${"─".repeat(o.length+4)}`))}export function printKeyValue(o,t){console.log(` ${chalk.gray(`${o}:`)} ${e.fg(t)}`)}
|
package/dist/lib/version.js
CHANGED
|
@@ -1,24 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
const __dirname_version = dirname(fileURLToPath(import.meta.url));
|
|
5
|
-
let _cached = null;
|
|
6
|
-
/**
|
|
7
|
-
* Returns the running CLI's package.json version, cached after first call.
|
|
8
|
-
* Used by interaction events + log-sync payload so future forensic audits
|
|
9
|
-
* can pinpoint which CLI version produced any given event. Added in
|
|
10
|
-
* v2.19.185 in response to the Paper E dispatcher bug, where we couldn't
|
|
11
|
-
* tell from the data which contestants ran pre-fix vs post-fix code.
|
|
12
|
-
*/
|
|
13
|
-
export function getCliVersion() {
|
|
14
|
-
if (_cached)
|
|
15
|
-
return _cached;
|
|
16
|
-
try {
|
|
17
|
-
const pkg = JSON.parse(readFileSync(join(__dirname_version, '..', '..', 'package.json'), 'utf-8'));
|
|
18
|
-
_cached = pkg.version || 'unknown';
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
_cached = 'unknown';
|
|
22
|
-
}
|
|
23
|
-
return _cached;
|
|
24
|
-
}
|
|
1
|
+
import{readFileSync as n}from"node:fs";import{dirname as o,join as r}from"node:path";import{fileURLToPath as t}from"node:url";const e=o(t(import.meta.url));let i=null;export function getCliVersion(){if(i)return i;try{const o=JSON.parse(n(r(e,"..","..","package.json"),"utf-8"));i=o.version||"unknown"}catch{i="unknown"}return i}
|
package/dist/postinstall.js
CHANGED
|
@@ -1,49 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
* Post-install script: shows a progress bar during ICOA CLI setup.
|
|
4
|
-
* Runs automatically after `npm install -g icoa-cli`.
|
|
5
|
-
*/
|
|
6
|
-
const steps = [
|
|
7
|
-
'Initializing ICOA CLI...',
|
|
8
|
-
'Loading competition modules...',
|
|
9
|
-
'Configuring exam system...',
|
|
10
|
-
'Setting up references...',
|
|
11
|
-
'Finalizing installation...',
|
|
12
|
-
];
|
|
13
|
-
const BAR_WIDTH = 30;
|
|
14
|
-
const TOTAL = 100;
|
|
15
|
-
function drawBar(percent, label) {
|
|
16
|
-
const filled = Math.round((percent / TOTAL) * BAR_WIDTH);
|
|
17
|
-
const empty = BAR_WIDTH - filled;
|
|
18
|
-
const bar = `\x1b[32m${'█'.repeat(filled)}\x1b[90m${'░'.repeat(empty)}\x1b[0m`;
|
|
19
|
-
const pct = `${String(percent).padStart(3)}%`;
|
|
20
|
-
process.stdout.write(`\r ${bar} ${pct} \x1b[90m${label}\x1b[0m`);
|
|
21
|
-
}
|
|
22
|
-
async function run() {
|
|
23
|
-
console.log();
|
|
24
|
-
console.log(' \x1b[1m\x1b[37m██╗ ██████╗ ██████╗ █████╗\x1b[0m');
|
|
25
|
-
console.log(' \x1b[1m\x1b[37m██║██╔════╝██╔═══██╗██╔══██╗\x1b[0m');
|
|
26
|
-
console.log(' \x1b[1m\x1b[37m██║██║ ██║ ██║███████║\x1b[0m');
|
|
27
|
-
console.log(' \x1b[1m\x1b[37m██║██║ ██║ ██║██╔══██║\x1b[0m');
|
|
28
|
-
console.log(' \x1b[1m\x1b[37m██║╚██████╗╚██████╔╝██║ ██║\x1b[0m');
|
|
29
|
-
console.log(' \x1b[1m\x1b[37m╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝\x1b[0m');
|
|
30
|
-
console.log();
|
|
31
|
-
for (let i = 0; i < steps.length; i++) {
|
|
32
|
-
const startPct = Math.round((i / steps.length) * TOTAL);
|
|
33
|
-
const endPct = Math.round(((i + 1) / steps.length) * TOTAL);
|
|
34
|
-
for (let p = startPct; p <= endPct; p++) {
|
|
35
|
-
drawBar(p, steps[i]);
|
|
36
|
-
await new Promise((r) => setTimeout(r, 15));
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
console.log();
|
|
40
|
-
console.log();
|
|
41
|
-
console.log(' \x1b[32m✓\x1b[0m ICOA CLI installed successfully!');
|
|
42
|
-
console.log();
|
|
43
|
-
console.log(' \x1b[90mGet started:\x1b[0m');
|
|
44
|
-
console.log(' \x1b[1m\x1b[37micoa\x1b[0m \x1b[90mLaunch and select your mode\x1b[0m');
|
|
45
|
-
console.log(' \x1b[1m\x1b[37micoa --help\x1b[0m \x1b[90mShow all commands\x1b[0m');
|
|
46
|
-
console.log();
|
|
47
|
-
}
|
|
48
|
-
run().catch(() => { });
|
|
49
|
-
export {};
|
|
2
|
+
const o=["Initializing ICOA CLI...","Loading competition modules...","Configuring exam system...","Setting up references...","Finalizing installation..."];function l(o,l){const e=Math.round(o/100*30),n=30-e,m=`[32m${"█".repeat(e)}[90m${"░".repeat(n)}[0m`,t=`${String(o).padStart(3)}%`;process.stdout.write(`\r ${m} ${t} [90m${l}[0m`)}(async function(){console.log(),console.log(" [1m[37m██╗ ██████╗ ██████╗ █████╗[0m"),console.log(" [1m[37m██║██╔════╝██╔═══██╗██╔══██╗[0m"),console.log(" [1m[37m██║██║ ██║ ██║███████║[0m"),console.log(" [1m[37m██║██║ ██║ ██║██╔══██║[0m"),console.log(" [1m[37m██║╚██████╗╚██████╔╝██║ ██║[0m"),console.log(" [1m[37m╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝[0m"),console.log();for(let e=0;e<o.length;e++){const n=Math.round(e/o.length*100),m=Math.round((e+1)/o.length*100);for(let t=n;t<=m;t++)l(t,o[e]),await new Promise(o=>setTimeout(o,15))}console.log(),console.log(),console.log(" [32m✓[0m ICOA CLI installed successfully!"),console.log(),console.log(" [90mGet started:[0m"),console.log(" [1m[37micoa[0m [90mLaunch and select your mode[0m"),console.log(" [1m[37micoa --help[0m [90mShow all commands[0m"),console.log()})().catch(()=>{});export{};
|