icoa-cli 1.6.2 → 1.7.1

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