icoa-cli 1.6.2 → 1.7.0
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/env.js +231 -114
- package/dist/index.js +1 -1
- package/dist/repl.js +1 -1
- package/package.json +1 -1
package/dist/commands/env.js
CHANGED
|
@@ -1,72 +1,141 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import { platform } from 'node:os';
|
|
4
|
+
// ══════════════════════════════════════════════════════════
|
|
5
|
+
// 27 Python Libraries — ALL LOCKED VERSIONS
|
|
6
|
+
// Tested on Python 3.12.x (recommended)
|
|
7
|
+
// ══════════════════════════════════════════════════════════
|
|
4
8
|
const PYTHON_LIBS = [
|
|
5
|
-
|
|
6
|
-
{ name: '
|
|
7
|
-
{ name: '
|
|
8
|
-
{ name: '
|
|
9
|
-
{ name: '
|
|
10
|
-
|
|
11
|
-
{ name: '
|
|
12
|
-
{ name: '
|
|
13
|
-
{ name: '
|
|
14
|
-
{ name: '
|
|
15
|
-
{ name: '
|
|
16
|
-
|
|
17
|
-
{ name: '
|
|
18
|
-
{ name: '
|
|
19
|
-
{ name: 'cryptography', check: 'python3 -c "import cryptography"', install: 'cryptography==42.0.0', category: '
|
|
20
|
-
|
|
21
|
-
{ name: '
|
|
22
|
-
{ name: '
|
|
23
|
-
{ name: '
|
|
24
|
-
{ name: '
|
|
9
|
+
// Core CTF
|
|
10
|
+
{ name: 'pwntools', check: 'python3 -c "import pwn"', install: 'pwntools==4.12.0', category: 'CTF Core' },
|
|
11
|
+
{ name: 'pycryptodome', check: 'python3 -c "import Crypto"', install: 'pycryptodome==3.20.0', category: 'CTF Core' },
|
|
12
|
+
{ name: 'z3-solver', check: 'python3 -c "import z3"', install: 'z3-solver==4.12.6', category: 'CTF Core' },
|
|
13
|
+
{ name: 'angr', check: 'python3 -c "import angr"', install: 'angr', category: 'CTF Core' },
|
|
14
|
+
// Networking & Web
|
|
15
|
+
{ name: 'requests', check: 'python3 -c "import requests"', install: 'requests==2.31.0', category: 'Web & Network' },
|
|
16
|
+
{ name: 'beautifulsoup4', check: 'python3 -c "import bs4"', install: 'beautifulsoup4==4.12.3', category: 'Web & Network' },
|
|
17
|
+
{ name: 'flask', check: 'python3 -c "import flask"', install: 'flask==3.0.0', category: 'Web & Network' },
|
|
18
|
+
{ name: 'scapy', check: 'python3 -c "import scapy"', install: 'scapy==2.5.0', category: 'Web & Network' },
|
|
19
|
+
{ name: 'paramiko', check: 'python3 -c "import paramiko"', install: 'paramiko==3.4.0', category: 'Web & Network' },
|
|
20
|
+
// Crypto & Math
|
|
21
|
+
{ name: 'sympy', check: 'python3 -c "import sympy"', install: 'sympy==1.12', category: 'Crypto & Math' },
|
|
22
|
+
{ name: 'gmpy2', check: 'python3 -c "import gmpy2"', install: 'gmpy2==2.1.5', category: 'Crypto & Math' },
|
|
23
|
+
{ name: 'cryptography', check: 'python3 -c "import cryptography"', install: 'cryptography==42.0.0', category: 'Crypto & Math' },
|
|
24
|
+
// Binary & RE
|
|
25
|
+
{ name: 'capstone', check: 'python3 -c "import capstone"', install: 'capstone==5.0.1', category: 'Binary & RE' },
|
|
26
|
+
{ name: 'ropper', check: 'python3 -c "import ropper"', install: 'ropper==1.13.8', category: 'Binary & RE' },
|
|
27
|
+
{ name: 'ROPgadget', check: 'which ROPgadget', install: 'ROPgadget==7.4', category: 'Binary & RE' },
|
|
28
|
+
{ name: 'pefile', check: 'python3 -c "import pefile"', install: 'pefile==2023.2.7', category: 'Binary & RE' },
|
|
29
|
+
// Data & Forensics
|
|
30
|
+
{ name: 'pillow', check: 'python3 -c "import PIL"', install: 'pillow==10.2.0', category: 'Data & Forensics' },
|
|
31
|
+
{ name: 'numpy', check: 'python3 -c "import numpy"', install: 'numpy==1.26.4', category: 'Data & Forensics' },
|
|
32
|
+
{ name: 'python-magic', check: 'python3 -c "import magic"', install: 'python-magic==0.4.27', category: 'Data & Forensics' },
|
|
33
|
+
{ name: 'yara-python', check: 'python3 -c "import yara"', install: 'yara-python==4.5.0', category: 'Data & Forensics' },
|
|
34
|
+
// Tools
|
|
35
|
+
{ name: 'sqlmap', check: 'which sqlmap', install: 'sqlmap', category: 'Security Tools' },
|
|
36
|
+
{ name: 'ipython', check: 'which ipython3 || which ipython', install: 'ipython', category: 'Security Tools' },
|
|
37
|
+
{ name: 'uncompyle6', check: 'python3 -c "import uncompyle6"', install: 'uncompyle6==3.9.1', category: 'Security Tools' },
|
|
38
|
+
{ name: 'rsactftool', check: 'which rsactftool || python3 -c "import rsactftool"', install: 'rsactftool', category: 'Security Tools' },
|
|
39
|
+
{ name: 'pngcheck', check: 'python3 -c "import pngcheck"', install: 'pngcheck', category: 'Security Tools' },
|
|
40
|
+
{ name: 'volatility3', check: 'python3 -c "import volatility3"', install: 'volatility3', category: 'Security Tools' },
|
|
41
|
+
{ name: 'pyserial', check: 'python3 -c "import serial"', install: 'pyserial==3.5', category: 'Security Tools' },
|
|
25
42
|
];
|
|
43
|
+
// ══════════════════════════════════════════════════════════
|
|
44
|
+
// 82 System Tools — with brew/apt install commands
|
|
45
|
+
// ══════════════════════════════════════════════════════════
|
|
26
46
|
const SYSTEM_TOOLS = [
|
|
27
|
-
// Editors
|
|
28
|
-
{ name: 'vim', check: 'which vim', category: 'Editors' },
|
|
29
|
-
{ name: 'nano', check: 'which nano', category: 'Editors' },
|
|
30
|
-
{ name: 'tmux', check: 'which tmux', category: 'Editors' },
|
|
31
|
-
|
|
32
|
-
{ name: '
|
|
33
|
-
|
|
34
|
-
{ name: '
|
|
35
|
-
{ name: '
|
|
36
|
-
|
|
37
|
-
{ name: '
|
|
38
|
-
{ name: '
|
|
39
|
-
|
|
40
|
-
{ name: '
|
|
41
|
-
{ name: '
|
|
42
|
-
|
|
43
|
-
{ name: '
|
|
44
|
-
{ name: '
|
|
45
|
-
{ name: '
|
|
46
|
-
//
|
|
47
|
-
{ name: '
|
|
48
|
-
{ name: '
|
|
49
|
-
{ name: '
|
|
50
|
-
|
|
51
|
-
{ name: '
|
|
52
|
-
{ name: '
|
|
53
|
-
|
|
54
|
-
{ name: '
|
|
55
|
-
{ name: '
|
|
56
|
-
{ name: '
|
|
57
|
-
{ name: '
|
|
47
|
+
// Editors & Terminal (5)
|
|
48
|
+
{ name: 'vim', check: 'which vim', brew: 'vim', apt: 'vim', category: 'Editors & Terminal' },
|
|
49
|
+
{ name: 'nano', check: 'which nano', brew: 'nano', apt: 'nano', category: 'Editors & Terminal' },
|
|
50
|
+
{ name: 'tmux', check: 'which tmux', brew: 'tmux', apt: 'tmux', category: 'Editors & Terminal' },
|
|
51
|
+
{ name: 'screen', check: 'which screen', brew: 'screen', apt: 'screen', category: 'Editors & Terminal' },
|
|
52
|
+
{ name: 'less', check: 'which less', category: 'Editors & Terminal' },
|
|
53
|
+
// Compilers & Build (8)
|
|
54
|
+
{ name: 'gcc', check: 'which gcc', brew: 'gcc', apt: 'gcc', category: 'Compilers & Build' },
|
|
55
|
+
{ name: 'g++', check: 'which g++', brew: 'gcc', apt: 'g++', category: 'Compilers & Build' },
|
|
56
|
+
{ name: 'make', check: 'which make', brew: 'make', apt: 'make', category: 'Compilers & Build' },
|
|
57
|
+
{ name: 'nasm', check: 'which nasm', brew: 'nasm', apt: 'nasm', category: 'Compilers & Build' },
|
|
58
|
+
{ name: 'cmake', check: 'which cmake', brew: 'cmake', apt: 'cmake', category: 'Compilers & Build' },
|
|
59
|
+
{ name: 'as', check: 'which as', category: 'Compilers & Build' },
|
|
60
|
+
{ name: 'ld', check: 'which ld', category: 'Compilers & Build' },
|
|
61
|
+
{ name: 'pkg-config', check: 'which pkg-config', brew: 'pkg-config', apt: 'pkg-config', category: 'Compilers & Build' },
|
|
62
|
+
// Python (3)
|
|
63
|
+
{ name: 'python3', check: 'python3 --version', brew: 'python@3.12', apt: 'python3', category: 'Python Runtime' },
|
|
64
|
+
{ name: 'pip3', check: 'pip3 --version', category: 'Python Runtime' },
|
|
65
|
+
{ name: 'python3-venv', check: 'python3 -c "import venv"', apt: 'python3-venv', category: 'Python Runtime' },
|
|
66
|
+
// Networking (12)
|
|
67
|
+
{ name: 'curl', check: 'which curl', brew: 'curl', apt: 'curl', category: 'Networking' },
|
|
68
|
+
{ name: 'wget', check: 'which wget', brew: 'wget', apt: 'wget', category: 'Networking' },
|
|
69
|
+
{ name: 'nc', check: 'which nc', brew: 'netcat', apt: 'netcat-openbsd', category: 'Networking' },
|
|
70
|
+
{ name: 'socat', check: 'which socat', brew: 'socat', apt: 'socat', category: 'Networking' },
|
|
71
|
+
{ name: 'nmap', check: 'which nmap', brew: 'nmap', apt: 'nmap', category: 'Networking' },
|
|
72
|
+
{ name: 'ssh', check: 'which ssh', apt: 'openssh-client', category: 'Networking' },
|
|
73
|
+
{ name: 'dig', check: 'which dig', brew: 'bind', apt: 'dnsutils', category: 'Networking' },
|
|
74
|
+
{ name: 'whois', check: 'which whois', brew: 'whois', apt: 'whois', category: 'Networking' },
|
|
75
|
+
{ name: 'ping', check: 'which ping', apt: 'iputils-ping', category: 'Networking' },
|
|
76
|
+
{ name: 'traceroute', check: 'which traceroute', brew: 'traceroute', apt: 'traceroute', category: 'Networking' },
|
|
77
|
+
{ name: 'tcpdump', check: 'which tcpdump', brew: 'tcpdump', apt: 'tcpdump', category: 'Networking' },
|
|
78
|
+
{ name: 'tshark', check: 'which tshark', brew: 'wireshark', apt: 'tshark', category: 'Networking' },
|
|
79
|
+
// Debuggers & Tracing (5)
|
|
80
|
+
{ name: 'gdb', check: 'which gdb', brew: 'gdb', apt: 'gdb', category: 'Debuggers' },
|
|
81
|
+
{ name: 'ltrace', check: 'which ltrace', apt: 'ltrace', category: 'Debuggers' },
|
|
82
|
+
{ name: 'strace', check: 'which strace', apt: 'strace', category: 'Debuggers' },
|
|
83
|
+
{ name: 'objdump', check: 'which objdump', category: 'Debuggers' },
|
|
84
|
+
{ name: 'readelf', check: 'which readelf', category: 'Debuggers' },
|
|
85
|
+
// Reverse Engineering (4)
|
|
86
|
+
{ name: 'radare2', check: 'which r2', brew: 'radare2', apt: 'radare2', category: 'Reverse Engineering' },
|
|
87
|
+
{ name: 'rabin2', check: 'which rabin2', category: 'Reverse Engineering' },
|
|
88
|
+
{ name: 'upx', check: 'which upx', brew: 'upx', apt: 'upx', category: 'Reverse Engineering' },
|
|
89
|
+
{ name: 'strings', check: 'which strings', category: 'Reverse Engineering' },
|
|
90
|
+
// Forensics (7)
|
|
91
|
+
{ name: 'binwalk', check: 'which binwalk', brew: 'binwalk', apt: 'binwalk', category: 'Forensics' },
|
|
92
|
+
{ name: 'foremost', check: 'which foremost', apt: 'foremost', category: 'Forensics' },
|
|
93
|
+
{ name: 'exiftool', check: 'which exiftool', brew: 'exiftool', apt: 'exiftool', category: 'Forensics' },
|
|
94
|
+
{ name: 'steghide', check: 'which steghide', apt: 'steghide', category: 'Forensics' },
|
|
58
95
|
{ name: 'file', check: 'which file', category: 'Forensics' },
|
|
59
|
-
{ name: 'xxd', check: 'which xxd', category: 'Forensics' },
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
{ name: '
|
|
63
|
-
{ name: '
|
|
64
|
-
|
|
65
|
-
{ name: '
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{ name: '
|
|
69
|
-
{ name: '
|
|
96
|
+
{ name: 'xxd', check: 'which xxd', brew: 'vim', apt: 'xxd', category: 'Forensics' },
|
|
97
|
+
{ name: 'pdftotext', check: 'which pdftotext', brew: 'poppler', apt: 'poppler-utils', category: 'Forensics' },
|
|
98
|
+
// Crypto & Password (4)
|
|
99
|
+
{ name: 'john', check: 'which john', brew: 'john', apt: 'john', category: 'Crypto & Password' },
|
|
100
|
+
{ name: 'hashcat', check: 'which hashcat', brew: 'hashcat', apt: 'hashcat', category: 'Crypto & Password' },
|
|
101
|
+
{ name: 'openssl', check: 'which openssl', category: 'Crypto & Password' },
|
|
102
|
+
{ name: 'gpg', check: 'which gpg', brew: 'gnupg', apt: 'gpg', category: 'Crypto & Password' },
|
|
103
|
+
// Data Processing (8)
|
|
104
|
+
{ name: 'jq', check: 'which jq', brew: 'jq', apt: 'jq', category: 'Data Processing' },
|
|
105
|
+
{ name: 'sqlite3', check: 'which sqlite3', brew: 'sqlite', apt: 'sqlite3', category: 'Data Processing' },
|
|
106
|
+
{ name: 'base64', check: 'which base64', category: 'Data Processing' },
|
|
107
|
+
{ name: 'hexdump', check: 'which hexdump', category: 'Data Processing' },
|
|
108
|
+
{ name: 'od', check: 'which od', category: 'Data Processing' },
|
|
109
|
+
{ name: 'sort', check: 'which sort', category: 'Data Processing' },
|
|
110
|
+
{ name: 'uniq', check: 'which uniq', category: 'Data Processing' },
|
|
111
|
+
{ name: 'wc', check: 'which wc', category: 'Data Processing' },
|
|
112
|
+
// Archive (6)
|
|
113
|
+
{ name: 'unzip', check: 'which unzip', brew: 'unzip', apt: 'unzip', category: 'Archive' },
|
|
114
|
+
{ name: 'zip', check: 'which zip', brew: 'zip', apt: 'zip', category: 'Archive' },
|
|
115
|
+
{ name: 'tar', check: 'which tar', category: 'Archive' },
|
|
116
|
+
{ name: 'gzip', check: 'which gzip', category: 'Archive' },
|
|
117
|
+
{ name: 'bzip2', check: 'which bzip2', category: 'Archive' },
|
|
118
|
+
{ name: 'xz', check: 'which xz', brew: 'xz', apt: 'xz-utils', category: 'Archive' },
|
|
119
|
+
// Core Unix (16)
|
|
120
|
+
{ name: 'cat', check: 'which cat', category: 'Core Unix' },
|
|
121
|
+
{ name: 'grep', check: 'which grep', category: 'Core Unix' },
|
|
122
|
+
{ name: 'sed', check: 'which sed', category: 'Core Unix' },
|
|
123
|
+
{ name: 'awk', check: 'which awk', category: 'Core Unix' },
|
|
124
|
+
{ name: 'find', check: 'which find', category: 'Core Unix' },
|
|
125
|
+
{ name: 'head', check: 'which head', category: 'Core Unix' },
|
|
126
|
+
{ name: 'tail', check: 'which tail', category: 'Core Unix' },
|
|
127
|
+
{ name: 'diff', check: 'which diff', category: 'Core Unix' },
|
|
128
|
+
{ name: 'patch', check: 'which patch', category: 'Core Unix' },
|
|
129
|
+
{ name: 'chmod', check: 'which chmod', category: 'Core Unix' },
|
|
130
|
+
{ name: 'chown', check: 'which chown', category: 'Core Unix' },
|
|
131
|
+
{ name: 'ln', check: 'which ln', category: 'Core Unix' },
|
|
132
|
+
{ name: 'cp', check: 'which cp', category: 'Core Unix' },
|
|
133
|
+
{ name: 'mv', check: 'which mv', category: 'Core Unix' },
|
|
134
|
+
{ name: 'mkdir', check: 'which mkdir', category: 'Core Unix' },
|
|
135
|
+
{ name: 'rm', check: 'which rm', category: 'Core Unix' },
|
|
136
|
+
// Version Control & Container (2)
|
|
137
|
+
{ name: 'git', check: 'which git', brew: 'git', apt: 'git', category: 'Git & Docker' },
|
|
138
|
+
{ name: 'docker', check: 'which docker', brew: '--cask docker', category: 'Git & Docker' },
|
|
70
139
|
];
|
|
71
140
|
function isInstalled(check) {
|
|
72
141
|
try {
|
|
@@ -79,54 +148,67 @@ function isInstalled(check) {
|
|
|
79
148
|
}
|
|
80
149
|
function getVersion(name) {
|
|
81
150
|
try {
|
|
82
|
-
if (name === 'python3')
|
|
151
|
+
if (name === 'python3')
|
|
83
152
|
return execSync('python3 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
|
|
84
|
-
}
|
|
85
153
|
if (name === 'gcc') {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
return match ? match[1] : '';
|
|
154
|
+
const m = execSync('gcc --version', { encoding: 'utf-8' }).match(/(\d+\.\d+[\.\d]*)/);
|
|
155
|
+
return m?.[1] || '';
|
|
89
156
|
}
|
|
90
157
|
if (name === 'docker') {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
158
|
+
const m = execSync('docker --version', { encoding: 'utf-8' }).match(/(\d+\.\d+\.\d+)/);
|
|
159
|
+
return m?.[1] || '';
|
|
160
|
+
}
|
|
161
|
+
if (name === 'pip3') {
|
|
162
|
+
const m = execSync('pip3 --version', { encoding: 'utf-8' }).match(/(\d+\.\d+[\.\d]*)/);
|
|
163
|
+
return m?.[1] || '';
|
|
164
|
+
}
|
|
165
|
+
if (name === 'nmap') {
|
|
166
|
+
const m = execSync('nmap --version', { encoding: 'utf-8' }).match(/(\d+\.\d+)/);
|
|
167
|
+
return m?.[1] || '';
|
|
94
168
|
}
|
|
95
169
|
}
|
|
96
170
|
catch { /* ignore */ }
|
|
97
171
|
return '';
|
|
98
172
|
}
|
|
173
|
+
function getPythonMajorMinor() {
|
|
174
|
+
try {
|
|
175
|
+
return execSync('python3 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"', { encoding: 'utf-8' }).trim();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return '';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
99
181
|
export function registerEnvCommand(program) {
|
|
100
182
|
const envCmd = program.command('env').description('Manage competition environment');
|
|
101
|
-
|
|
102
|
-
envCmd
|
|
103
|
-
|
|
104
|
-
.alias('check')
|
|
105
|
-
.description('Check installed tools and libraries')
|
|
106
|
-
.action(() => {
|
|
107
|
-
showStatus();
|
|
108
|
-
});
|
|
109
|
-
// icoa env setup — install everything
|
|
110
|
-
envCmd
|
|
111
|
-
.command('setup')
|
|
112
|
-
.description('Install all Python libraries (locked versions)')
|
|
113
|
-
.action(async () => {
|
|
114
|
-
await installAll();
|
|
115
|
-
});
|
|
116
|
-
// Default action: show status
|
|
117
|
-
envCmd.action(() => {
|
|
118
|
-
showStatus();
|
|
119
|
-
});
|
|
183
|
+
envCmd.command('status').alias('check').description('Check all 109 tools').action(() => showStatus());
|
|
184
|
+
envCmd.command('setup').description('Install all Python libraries + system tools').action(async () => { await installAll(); });
|
|
185
|
+
envCmd.action(() => showStatus());
|
|
120
186
|
}
|
|
121
187
|
function showStatus() {
|
|
122
188
|
console.log();
|
|
123
|
-
console.log(chalk.bold.white(' ICOA Competition Environment'));
|
|
124
|
-
console.log(chalk.gray('
|
|
189
|
+
console.log(chalk.bold.white(' ICOA Competition Environment (109 commands)'));
|
|
190
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
191
|
+
// Python version check
|
|
192
|
+
const pyVer = getPythonMajorMinor();
|
|
193
|
+
if (pyVer) {
|
|
194
|
+
const fullVer = getVersion('python3');
|
|
195
|
+
if (pyVer === '3.12') {
|
|
196
|
+
console.log(chalk.green(` ✓ Python ${fullVer}`) + chalk.gray(' (recommended)'));
|
|
197
|
+
}
|
|
198
|
+
else if (pyVer === '3.11' || pyVer === '3.13') {
|
|
199
|
+
console.log(chalk.yellow(` ~ Python ${fullVer}`) + chalk.gray(' (3.12.x recommended for full compatibility)'));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log(chalk.red(` ✗ Python ${fullVer}`) + chalk.gray(' (3.12.x required — some tools may not work)'));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log(chalk.red(' ✗ Python 3 not found'));
|
|
207
|
+
}
|
|
125
208
|
console.log();
|
|
126
209
|
let installed = 0;
|
|
127
210
|
let missing = 0;
|
|
128
211
|
let currentCategory = '';
|
|
129
|
-
// System tools
|
|
130
212
|
for (const tool of SYSTEM_TOOLS) {
|
|
131
213
|
if (tool.category !== currentCategory) {
|
|
132
214
|
currentCategory = tool.category;
|
|
@@ -144,7 +226,6 @@ function showStatus() {
|
|
|
144
226
|
missing++;
|
|
145
227
|
}
|
|
146
228
|
}
|
|
147
|
-
// Python libraries
|
|
148
229
|
currentCategory = '';
|
|
149
230
|
for (const lib of PYTHON_LIBS) {
|
|
150
231
|
if (lib.category !== currentCategory) {
|
|
@@ -152,57 +233,93 @@ function showStatus() {
|
|
|
152
233
|
console.log(chalk.bold.gray(` ${currentCategory}`));
|
|
153
234
|
}
|
|
154
235
|
const ok = isInstalled(lib.check);
|
|
155
|
-
const verStr = lib.install ? chalk.gray(` (${lib.install})`) : '';
|
|
156
236
|
if (ok) {
|
|
157
|
-
console.log(chalk.green(` ✓ ${lib.name}`) +
|
|
237
|
+
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(` (${lib.install || 'latest'})`));
|
|
158
238
|
installed++;
|
|
159
239
|
}
|
|
160
240
|
else {
|
|
161
|
-
console.log(chalk.red(` ✗ ${lib.name}`) +
|
|
241
|
+
console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(` → ${lib.install || 'latest'}`));
|
|
162
242
|
missing++;
|
|
163
243
|
}
|
|
164
244
|
}
|
|
245
|
+
const total = installed + missing;
|
|
165
246
|
console.log();
|
|
166
|
-
console.log(chalk.gray('
|
|
167
|
-
console.log(` ${chalk.green(`✓ ${installed}
|
|
247
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
248
|
+
console.log(` ${chalk.green(`✓ ${installed}/${total}`)} ${missing > 0 ? chalk.red(`✗ ${missing} missing`) : chalk.green('All 109 ready!')}`);
|
|
168
249
|
if (missing > 0) {
|
|
169
|
-
console.log();
|
|
170
|
-
console.log(chalk.gray(' Install missing Python libs: ') + chalk.white('env setup'));
|
|
250
|
+
console.log(chalk.gray(' Install everything: ') + chalk.white('env setup'));
|
|
171
251
|
}
|
|
172
252
|
console.log();
|
|
173
253
|
}
|
|
174
254
|
async function installAll() {
|
|
175
|
-
console.log();
|
|
176
|
-
console.log(chalk.bold.white(' Installing Python libraries (locked versions)...'));
|
|
177
255
|
console.log();
|
|
178
256
|
const os = platform();
|
|
179
257
|
const pipFlag = os === 'darwin' || os === 'linux' ? '--break-system-packages' : '';
|
|
180
|
-
|
|
181
|
-
|
|
258
|
+
// Python version warning
|
|
259
|
+
const pyVer = getPythonMajorMinor();
|
|
260
|
+
if (pyVer && pyVer !== '3.12') {
|
|
261
|
+
console.log(chalk.yellow(` Note: Python ${pyVer} detected. Python 3.12.x recommended.`));
|
|
262
|
+
console.log();
|
|
263
|
+
}
|
|
264
|
+
// Install system tools via brew (macOS) or apt (Linux)
|
|
265
|
+
if (os === 'darwin' || os === 'linux') {
|
|
266
|
+
const missingSystem = [];
|
|
267
|
+
for (const tool of SYSTEM_TOOLS) {
|
|
268
|
+
if (!isInstalled(tool.check)) {
|
|
269
|
+
const pkg = os === 'darwin' ? tool.brew : tool.apt;
|
|
270
|
+
if (pkg)
|
|
271
|
+
missingSystem.push(tool);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (missingSystem.length > 0) {
|
|
275
|
+
const pm = os === 'darwin' ? 'brew' : 'sudo apt-get';
|
|
276
|
+
console.log(chalk.bold.white(` System Tools (${missingSystem.length} missing)`));
|
|
277
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
278
|
+
for (const tool of missingSystem) {
|
|
279
|
+
const pkg = os === 'darwin' ? tool.brew : tool.apt;
|
|
280
|
+
process.stdout.write(chalk.gray(` ⏳ ${tool.name}...`));
|
|
281
|
+
try {
|
|
282
|
+
const cmd = os === 'darwin' ? `brew install ${pkg}` : `sudo apt-get install -y ${pkg}`;
|
|
283
|
+
execSync(cmd, { stdio: 'ignore' });
|
|
284
|
+
process.stdout.write('\r');
|
|
285
|
+
console.log(chalk.green(` ✓ ${tool.name}`));
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
process.stdout.write('\r');
|
|
289
|
+
console.log(chalk.red(` ✗ ${tool.name}`) + chalk.gray(` (${pm} install ${os === 'darwin' ? tool.brew : tool.apt})`));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
console.log();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// Install Python libraries
|
|
296
|
+
let pipInstalled = 0;
|
|
297
|
+
let pipFailed = 0;
|
|
298
|
+
console.log(chalk.bold.white(` Python Libraries (${PYTHON_LIBS.length} packages)`));
|
|
299
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
182
300
|
for (const lib of PYTHON_LIBS) {
|
|
183
301
|
if (!lib.install)
|
|
184
302
|
continue;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
installed++;
|
|
303
|
+
if (isInstalled(lib.check)) {
|
|
304
|
+
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(' (installed)'));
|
|
305
|
+
pipInstalled++;
|
|
189
306
|
continue;
|
|
190
307
|
}
|
|
191
|
-
process.stdout.write(chalk.gray(` ⏳
|
|
308
|
+
process.stdout.write(chalk.gray(` ⏳ ${lib.name}...`));
|
|
192
309
|
try {
|
|
193
310
|
execSync(`pip3 install ${pipFlag} ${lib.install}`, { stdio: 'ignore' });
|
|
194
311
|
process.stdout.write('\r');
|
|
195
312
|
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(` (${lib.install})`));
|
|
196
|
-
|
|
313
|
+
pipInstalled++;
|
|
197
314
|
}
|
|
198
315
|
catch {
|
|
199
316
|
process.stdout.write('\r');
|
|
200
|
-
console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(
|
|
201
|
-
|
|
317
|
+
console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(' (failed)'));
|
|
318
|
+
pipFailed++;
|
|
202
319
|
}
|
|
203
320
|
}
|
|
204
321
|
console.log();
|
|
205
|
-
console.log(chalk.gray('
|
|
206
|
-
console.log(` ${chalk.green(`✓ ${
|
|
322
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
323
|
+
console.log(` ${chalk.green(`✓ ${pipInstalled} installed`)} ${pipFailed > 0 ? chalk.red(`✗ ${pipFailed} failed`) : chalk.green('All ready!')}`);
|
|
207
324
|
console.log();
|
|
208
325
|
}
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ ${LINE}
|
|
|
36
36
|
${chalk.white('Sydney, Australia')} ${chalk.gray('Jun 27 - Jul 2, 2026')}
|
|
37
37
|
${chalk.cyan.underline('https://icoa2026.au')}
|
|
38
38
|
|
|
39
|
-
${chalk.gray('CLI-Native Competition Terminal v1.
|
|
39
|
+
${chalk.gray('CLI-Native Competition Terminal v1.7.0')}
|
|
40
40
|
|
|
41
41
|
${LINE}
|
|
42
42
|
`;
|
package/dist/repl.js
CHANGED
|
@@ -6,7 +6,7 @@ import { isActivated, activateToken, isFreeCommand, isDeviceMatch, recordExit, r
|
|
|
6
6
|
import { resetTerminalTheme } from './lib/theme.js';
|
|
7
7
|
import { ensureSandbox, runInSandbox, isDockerAvailable } from './lib/sandbox.js';
|
|
8
8
|
const INTERCEPT = '__REPL_NO_EXIT__';
|
|
9
|
-
const VERSION = '1.
|
|
9
|
+
const VERSION = '1.7.0';
|
|
10
10
|
export async function startRepl(program, resumeMode) {
|
|
11
11
|
const config = getConfig();
|
|
12
12
|
const connected = isConnected();
|