icoa-cli 2.19.100 → 2.19.102

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.
Files changed (45) hide show
  1. package/dist/commands/ai4ctf.js +1 -700
  2. package/dist/commands/connect.js +1 -66
  3. package/dist/commands/ctf.js +1 -620
  4. package/dist/commands/ctf4ai-demo.js +1 -525
  5. package/dist/commands/env.js +1 -738
  6. package/dist/commands/exam.js +1 -2353
  7. package/dist/commands/files.js +1 -52
  8. package/dist/commands/hint.js +1 -119
  9. package/dist/commands/lang.js +1 -155
  10. package/dist/commands/log.js +1 -165
  11. package/dist/commands/note.js +1 -40
  12. package/dist/commands/ref.js +1 -68
  13. package/dist/commands/setup.js +1 -122
  14. package/dist/commands/shell.js +1 -55
  15. package/dist/commands/theme.js +1 -50
  16. package/dist/index.js +1 -225
  17. package/dist/lib/access.js +1 -246
  18. package/dist/lib/budget.js +1 -42
  19. package/dist/lib/colors.js +1 -21
  20. package/dist/lib/config.js +1 -60
  21. package/dist/lib/ctfd-client.js +1 -274
  22. package/dist/lib/demo-exam.js +1 -249
  23. package/dist/lib/demo-flags.js +1 -27
  24. package/dist/lib/demo-stats.js +1 -65
  25. package/dist/lib/exam-client.js +1 -57
  26. package/dist/lib/exam-setup.js +1 -23
  27. package/dist/lib/exam-state.js +1 -112
  28. package/dist/lib/gemini.js +1 -235
  29. package/dist/lib/i18n.js +1 -273
  30. package/dist/lib/log-sync.js +1 -110
  31. package/dist/lib/logger.js +1 -59
  32. package/dist/lib/paper-upgrade.js +1 -117
  33. package/dist/lib/platform.js +1 -86
  34. package/dist/lib/sandbox.js +1 -93
  35. package/dist/lib/terminal.js +1 -49
  36. package/dist/lib/theme.js +1 -108
  37. package/dist/lib/translation.js +1 -66
  38. package/dist/lib/ui.js +1 -80
  39. package/dist/lib/update-check.js +1 -102
  40. package/dist/postinstall.js +1 -48
  41. package/dist/repl.js +1 -1281
  42. package/dist/types/index.d.ts +1 -1
  43. package/dist/types/index.js +1 -38
  44. package/package.json +6 -2
  45. package/translations/sw/i18n-snippet.ts +1 -0
@@ -1,738 +1 @@
1
- import chalk from 'chalk';
2
- import { execSync } from 'node:child_process';
3
- import { platform } from 'node:os';
4
- // Target versions for full compatibility
5
- const PYTHON_TARGET = '3.12';
6
- const PYTHON_EXACT = '3.12.13';
7
- const NODE_TARGET = '22';
8
- const NODE_EXACT = '22.22.2';
9
- // ══════════════════════════════════════════════════════════
10
- // 27 Python Libraries — ALL LOCKED VERSIONS
11
- // Tested on Python 3.12.x (recommended)
12
- // ══════════════════════════════════════════════════════════
13
- const PYTHON_LIBS = [
14
- // Core CTF
15
- { name: 'pwntools', check: 'python3 -c "import pwn"', install: 'pwntools==4.12.0', category: 'CTF Core' },
16
- { name: 'pycryptodome', check: 'python3 -c "import Crypto"', install: 'pycryptodome==3.20.0', category: 'CTF Core' },
17
- { name: 'z3-solver', check: 'python3 -c "import z3"', install: 'z3-solver==4.12.6', category: 'CTF Core' },
18
- { name: 'angr', check: 'python3 -c "import angr"', install: 'angr', category: 'CTF Core' },
19
- // Networking & Web
20
- { name: 'requests', check: 'python3 -c "import requests"', install: 'requests==2.31.0', category: 'Web & Network' },
21
- { name: 'beautifulsoup4', check: 'python3 -c "import bs4"', install: 'beautifulsoup4==4.12.3', category: 'Web & Network' },
22
- { name: 'flask', check: 'python3 -c "import flask"', install: 'flask==3.0.0', category: 'Web & Network' },
23
- { name: 'scapy', check: 'python3 -c "import scapy"', install: 'scapy==2.5.0', category: 'Web & Network' },
24
- { name: 'paramiko', check: 'python3 -c "import paramiko"', install: 'paramiko==3.4.0', category: 'Web & Network' },
25
- // Crypto & Math
26
- { name: 'sympy', check: 'python3 -c "import sympy"', install: 'sympy==1.12', category: 'Crypto & Math' },
27
- { name: 'gmpy2', check: process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/python3.12 -c "import gmpy2"' : 'python3 -c "import gmpy2"', install: 'gmpy2>=2.2.0', category: 'Crypto & Math' },
28
- { name: 'cryptography', check: 'python3 -c "import cryptography"', install: 'cryptography==42.0.0', category: 'Crypto & Math' },
29
- // Binary & RE
30
- { name: 'capstone', check: 'python3 -c "import capstone"', install: 'capstone==5.0.1', category: 'Binary & RE' },
31
- { name: 'ropper', check: 'python3 -c "import ropper"', install: 'ropper==1.13.8', category: 'Binary & RE' },
32
- { name: 'ROPgadget', check: 'which ROPgadget', install: 'ROPgadget==7.4', category: 'Binary & RE' },
33
- { name: 'pefile', check: 'python3 -c "import pefile"', install: 'pefile==2023.2.7', category: 'Binary & RE' },
34
- // Data & Forensics
35
- { name: 'pillow', check: 'python3 -c "import PIL"', install: 'pillow==10.2.0', category: 'Data & Forensics' },
36
- { name: 'numpy', check: 'python3 -c "import numpy"', install: 'numpy==1.26.4', category: 'Data & Forensics' },
37
- { name: 'python-magic', check: 'python3 -c "import magic"', install: 'python-magic==0.4.27', category: 'Data & Forensics' },
38
- { name: 'yara-python', check: 'python3 -c "import yara"', install: 'yara-python==4.5.0', category: 'Data & Forensics' },
39
- // Tools
40
- { name: 'sqlmap', check: 'which sqlmap', install: 'sqlmap', category: 'Security Tools' },
41
- { name: 'ipython', check: 'which ipython3 || which ipython', install: 'ipython', category: 'Security Tools' },
42
- { name: 'uncompyle6', check: 'python3 -c "import uncompyle6"', install: 'uncompyle6==3.9.1', category: 'Security Tools' },
43
- { name: 'volatility3', check: 'python3 -c "import volatility3"', install: 'volatility3', category: 'Security Tools' },
44
- { name: 'pyserial', check: 'python3 -c "import serial"', install: 'pyserial==3.5', category: 'Security Tools' },
45
- ];
46
- // ══════════════════════════════════════════════════════════
47
- // 83 System Tools — brew (Mac) / apt (Ubuntu) / choco (Win)
48
- // ══════════════════════════════════════════════════════════
49
- const W = process.platform === 'win32';
50
- const CMD = (unix, win) => W ? (win || `where ${unix}`) : `which ${unix}`;
51
- const SYSTEM_TOOLS = [
52
- // Editors & Terminal (5)
53
- { name: 'vim', check: CMD('vim'), brew: 'vim', apt: 'vim', choco: 'vim', category: 'Editors & Terminal' },
54
- { name: 'nano', check: CMD('nano'), brew: 'nano', apt: 'nano', choco: 'nano', category: 'Editors & Terminal' },
55
- { name: 'tmux', check: CMD('tmux'), brew: 'tmux', apt: 'tmux', category: 'Editors & Terminal' },
56
- { name: 'screen', check: CMD('screen'), brew: 'screen', apt: 'screen', category: 'Editors & Terminal' },
57
- { name: 'less', check: CMD('less'), category: 'Editors & Terminal' },
58
- // Compilers & Build (8)
59
- { name: 'gcc', check: CMD('gcc'), brew: 'gcc', apt: 'gcc', choco: 'mingw', category: 'Compilers & Build' },
60
- { name: 'g++', check: CMD('g++'), brew: 'gcc', apt: 'g++', choco: 'mingw', category: 'Compilers & Build' },
61
- { name: 'make', check: CMD('make'), brew: 'make', apt: 'make', choco: 'make', category: 'Compilers & Build' },
62
- { name: 'nasm', check: CMD('nasm'), brew: 'nasm', apt: 'nasm', choco: 'nasm', category: 'Compilers & Build' },
63
- { name: 'cmake', check: CMD('cmake'), brew: 'cmake', apt: 'cmake', choco: 'cmake', category: 'Compilers & Build' },
64
- { name: 'as', check: CMD('as'), category: 'Compilers & Build' },
65
- { name: 'ld', check: CMD('ld'), category: 'Compilers & Build' },
66
- { name: 'pkg-config', check: CMD('pkg-config'), brew: 'pkg-config', apt: 'pkg-config', category: 'Compilers & Build' },
67
- // Python (3) — prefer brew 3.12 on macOS
68
- { name: 'python3', check: process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/python3.12 --version' : (W ? 'python --version' : 'python3 --version'), brew: 'python@3.12', apt: 'python3', choco: 'python312', category: 'Python Runtime' },
69
- { name: 'pip3', check: process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12 --version' : (W ? 'pip --version' : 'pip3 --version'), category: 'Python Runtime' },
70
- { name: 'python3-venv', check: W ? 'python -c "import venv"' : 'python3 -c "import venv"', apt: 'python3-venv', category: 'Python Runtime' },
71
- // Networking (12)
72
- { name: 'curl', check: CMD('curl'), brew: 'curl', apt: 'curl', choco: 'curl', category: 'Networking' },
73
- { name: 'wget', check: CMD('wget'), brew: 'wget', apt: 'wget', choco: 'wget', category: 'Networking' },
74
- { name: 'nc', check: CMD('nc', 'where ncat'), brew: 'netcat', apt: 'netcat-openbsd', choco: 'nmap', category: 'Networking' },
75
- { name: 'socat', check: CMD('socat'), brew: 'socat', apt: 'socat', category: 'Networking' },
76
- { name: 'nmap', check: CMD('nmap'), brew: 'nmap', apt: 'nmap', choco: 'nmap', category: 'Networking' },
77
- { name: 'ssh', check: CMD('ssh'), apt: 'openssh-client', category: 'Networking' },
78
- { name: 'dig', check: CMD('dig'), brew: 'bind', apt: 'dnsutils', category: 'Networking' },
79
- { name: 'whois', check: CMD('whois'), brew: 'whois', apt: 'whois', choco: 'whois', category: 'Networking' },
80
- { name: 'ping', check: CMD('ping'), apt: 'iputils-ping', category: 'Networking' },
81
- { name: 'traceroute', check: CMD('traceroute', 'where tracert'), brew: 'traceroute', apt: 'traceroute', category: 'Networking' },
82
- { name: 'tcpdump', check: CMD('tcpdump'), brew: 'tcpdump', apt: 'tcpdump', category: 'Networking' },
83
- { name: 'tshark', check: CMD('tshark'), brew: 'wireshark', apt: 'tshark', choco: 'wireshark', category: 'Networking' },
84
- // Debuggers & Tracing (5)
85
- { name: 'gdb', check: CMD('gdb'), brew: 'gdb', apt: 'gdb', choco: 'mingw', category: 'Debuggers' },
86
- ...(process.platform !== 'darwin' ? [
87
- { name: 'ltrace', check: CMD('ltrace'), apt: 'ltrace', category: 'Debuggers' },
88
- { name: 'strace', check: CMD('strace'), apt: 'strace', category: 'Debuggers' },
89
- ] : []),
90
- { name: 'objdump', check: CMD('objdump'), category: 'Debuggers' },
91
- ...(process.platform !== 'darwin' ? [
92
- { name: 'readelf', check: CMD('readelf'), category: 'Debuggers' },
93
- ] : []),
94
- // Reverse Engineering (4)
95
- { name: 'radare2', check: CMD('r2'), brew: 'radare2', apt: 'radare2', choco: 'radare2', category: 'Reverse Engineering' },
96
- { name: 'rabin2', check: CMD('rabin2'), category: 'Reverse Engineering' },
97
- { name: 'upx', check: CMD('upx'), brew: 'upx', apt: 'upx', choco: 'upx', category: 'Reverse Engineering' },
98
- { name: 'strings', check: CMD('strings'), category: 'Reverse Engineering' },
99
- // Forensics (7)
100
- { name: 'binwalk', check: CMD('binwalk'), brew: 'binwalk', apt: 'binwalk', category: 'Forensics' },
101
- ...(process.platform !== 'darwin' ? [
102
- { name: 'foremost', check: CMD('foremost'), apt: 'foremost', category: 'Forensics' },
103
- ] : []),
104
- { name: 'exiftool', check: CMD('exiftool'), brew: 'exiftool', apt: 'exiftool', choco: 'exiftool', category: 'Forensics' },
105
- ...(process.platform !== 'darwin' ? [
106
- { name: 'steghide', check: CMD('steghide'), apt: 'steghide', category: 'Forensics' },
107
- ] : []),
108
- { name: 'file', check: CMD('file'), category: 'Forensics' },
109
- { name: 'xxd', check: CMD('xxd'), brew: 'vim', apt: 'xxd', category: 'Forensics' },
110
- { name: 'pdftotext', check: CMD('pdftotext'), brew: 'poppler', apt: 'poppler-utils', category: 'Forensics' },
111
- { name: 'pngcheck', check: CMD('pngcheck'), brew: 'pngcheck', apt: 'pngcheck', category: 'Forensics' },
112
- // sleuthkit — disk-image forensics (mmls/fls/icat/blkcat + 20 more)
113
- { name: 'sleuthkit', check: CMD('mmls'), brew: 'sleuthkit', apt: 'sleuthkit', choco: 'sleuthkit', category: 'Forensics' },
114
- // Crypto & Password (4)
115
- { name: 'john', check: CMD('john'), brew: 'john', apt: 'john', choco: 'john', category: 'Crypto & Password' },
116
- { name: 'hashcat', check: CMD('hashcat'), brew: 'hashcat', apt: 'hashcat', choco: 'hashcat', category: 'Crypto & Password' },
117
- { name: 'openssl', check: CMD('openssl'), category: 'Crypto & Password' },
118
- { name: 'gpg', check: CMD('gpg'), brew: 'gnupg', apt: 'gpg', choco: 'gnupg', category: 'Crypto & Password' },
119
- // Data Processing (8)
120
- { name: 'jq', check: CMD('jq'), brew: 'jq', apt: 'jq', choco: 'jq', category: 'Data Processing' },
121
- { name: 'sqlite3', check: CMD('sqlite3'), brew: 'sqlite', apt: 'sqlite3', choco: 'sqlite', category: 'Data Processing' },
122
- { name: 'base64', check: CMD('base64'), category: 'Data Processing' },
123
- { name: 'hexdump', check: CMD('hexdump'), category: 'Data Processing' },
124
- { name: 'od', check: CMD('od'), category: 'Data Processing' },
125
- { name: 'sort', check: CMD('sort'), category: 'Data Processing' },
126
- { name: 'uniq', check: CMD('uniq'), category: 'Data Processing' },
127
- { name: 'wc', check: CMD('wc'), category: 'Data Processing' },
128
- // Archive (6)
129
- { name: 'unzip', check: CMD('unzip'), brew: 'unzip', apt: 'unzip', category: 'Archive' },
130
- { name: 'zip', check: CMD('zip'), brew: 'zip', apt: 'zip', category: 'Archive' },
131
- { name: 'tar', check: CMD('tar'), category: 'Archive' },
132
- { name: 'gzip', check: CMD('gzip'), category: 'Archive' },
133
- { name: 'bzip2', check: CMD('bzip2'), category: 'Archive' },
134
- { name: 'xz', check: CMD('xz'), brew: 'xz', apt: 'xz-utils', category: 'Archive' },
135
- // Core Unix (16)
136
- { name: 'cat', check: CMD('cat'), category: 'Core Unix' },
137
- { name: 'grep', check: CMD('grep'), category: 'Core Unix' },
138
- { name: 'sed', check: CMD('sed'), category: 'Core Unix' },
139
- { name: 'awk', check: CMD('awk'), category: 'Core Unix' },
140
- { name: 'find', check: CMD('find'), category: 'Core Unix' },
141
- { name: 'head', check: CMD('head'), category: 'Core Unix' },
142
- { name: 'tail', check: CMD('tail'), category: 'Core Unix' },
143
- { name: 'diff', check: CMD('diff'), category: 'Core Unix' },
144
- { name: 'patch', check: CMD('patch'), category: 'Core Unix' },
145
- { name: 'chmod', check: CMD('chmod'), category: 'Core Unix' },
146
- { name: 'chown', check: CMD('chown'), category: 'Core Unix' },
147
- { name: 'ln', check: CMD('ln'), category: 'Core Unix' },
148
- { name: 'cp', check: CMD('cp'), category: 'Core Unix' },
149
- { name: 'mv', check: CMD('mv'), category: 'Core Unix' },
150
- { name: 'mkdir', check: CMD('mkdir'), category: 'Core Unix' },
151
- { name: 'rm', check: CMD('rm'), category: 'Core Unix' },
152
- // Version Control & Container (2)
153
- { name: 'git', check: CMD('git'), brew: 'git', apt: 'git', choco: 'git', category: 'Git & Docker' },
154
- { name: 'docker', check: CMD('docker'), brew: '--cask docker', choco: 'docker-desktop', category: 'Git & Docker' },
155
- ];
156
- function isInstalled(check) {
157
- try {
158
- execSync(check, { stdio: 'ignore' });
159
- return true;
160
- }
161
- catch {
162
- return false;
163
- }
164
- }
165
- function getVersion(name) {
166
- // Version commands for each tool
167
- const versionCmds = {
168
- 'python3': process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/python3.12 --version' : 'python3 --version',
169
- 'pip3': process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12 --version' : 'pip3 --version',
170
- 'gcc': 'gcc --version',
171
- 'g++': 'g++ --version',
172
- 'make': 'make --version',
173
- 'nasm': 'nasm --version',
174
- 'cmake': 'cmake --version',
175
- 'vim': 'vim --version',
176
- 'nano': 'nano --version',
177
- 'tmux': 'tmux -V',
178
- 'screen': 'screen --version',
179
- 'curl': 'curl --version',
180
- 'wget': 'wget --version',
181
- 'nmap': 'nmap --version',
182
- 'ssh': 'ssh -V',
183
- 'socat': 'socat -V',
184
- 'gdb': 'gdb --version',
185
- 'radare2': 'r2 -v',
186
- 'upx': 'upx --version',
187
- 'binwalk': 'binwalk --help',
188
- 'exiftool': 'exiftool -ver',
189
- 'john': 'john --help',
190
- 'hashcat': 'hashcat --version',
191
- 'openssl': 'openssl version',
192
- 'gpg': 'gpg --version',
193
- 'jq': 'jq --version',
194
- 'sqlite3': 'sqlite3 --version',
195
- 'git': 'git --version',
196
- 'docker': 'docker --version',
197
- 'tshark': 'tshark --version',
198
- 'tcpdump': 'tcpdump --version',
199
- 'pdftotext': 'pdftotext -v',
200
- 'pngcheck': 'pngcheck 2>&1',
201
- };
202
- const cmd = versionCmds[name];
203
- if (!cmd)
204
- return '';
205
- try {
206
- const out = execSync(cmd + ' 2>&1', { encoding: 'utf-8', timeout: 3000 }).trim();
207
- // Extract version number pattern
208
- const m = out.match(/(\d+\.\d+[\.\d]*)/);
209
- return m?.[1] || '';
210
- }
211
- catch { /* ignore */ }
212
- return '';
213
- }
214
- function getOsInfo() {
215
- const os = platform();
216
- try {
217
- if (os === 'darwin') {
218
- const ver = execSync('sw_vers -productVersion', { encoding: 'utf-8' }).trim();
219
- const arch = execSync('uname -m', { encoding: 'utf-8' }).trim();
220
- return `macOS ${ver} (${arch})`;
221
- }
222
- else if (os === 'linux') {
223
- try {
224
- const pretty = execSync('cat /etc/os-release | grep PRETTY_NAME', { encoding: 'utf-8' });
225
- const m = pretty.match(/PRETTY_NAME="(.+)"/);
226
- const arch = execSync('uname -m', { encoding: 'utf-8' }).trim();
227
- return m ? `${m[1]} (${arch})` : `Linux (${arch})`;
228
- }
229
- catch {
230
- return 'Linux';
231
- }
232
- }
233
- else if (os === 'win32') {
234
- const ver = execSync('ver', { encoding: 'utf-8' }).trim();
235
- return ver || 'Windows';
236
- }
237
- }
238
- catch { /* ignore */ }
239
- return os;
240
- }
241
- function getNodeInfo() {
242
- return `Node.js ${process.version}`;
243
- }
244
- function getPythonMajorMinor() {
245
- // On macOS, prefer brew Python 3.12
246
- if (process.platform === 'darwin') {
247
- try {
248
- return execSync('/opt/homebrew/opt/python@3.12/bin/python3.12 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"', { encoding: 'utf-8' }).trim();
249
- }
250
- catch { /* fall through */ }
251
- }
252
- try {
253
- return execSync('python3 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"', { encoding: 'utf-8' }).trim();
254
- }
255
- catch {
256
- return '';
257
- }
258
- }
259
- function getPythonFullVersion() {
260
- if (process.platform === 'darwin') {
261
- try {
262
- return execSync('/opt/homebrew/opt/python@3.12/bin/python3.12 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
263
- }
264
- catch { /* fall through */ }
265
- }
266
- try {
267
- return execSync('python3 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
268
- }
269
- catch {
270
- return '';
271
- }
272
- }
273
- export function registerEnvCommand(program) {
274
- const envCmd = program.command('env').description('Manage competition environment');
275
- envCmd.command('status').alias('check').description('Check all 110 tools').action(() => showStatus());
276
- envCmd.command('setup').description('Install all Python libraries + system tools').action(async () => { await installAll(); });
277
- envCmd.command('python').description('Show Python 3.12 install guide for your platform').action(() => showPythonInstallGuide());
278
- envCmd.action(() => showStatus());
279
- }
280
- // Lightweight Python 3.12 install guide for Selection mode (no 110-tool check).
281
- // Detects distro on Linux so contestants get the right command the first time.
282
- function showPythonInstallGuide() {
283
- const os = platform();
284
- console.log();
285
- console.log(chalk.bold.white(' Python 3.12 — Installation Guide'));
286
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
287
- console.log();
288
- let currentPy = '';
289
- let pyStatus = 'missing';
290
- // Prefer the versioned binary if available. On macOS with Homebrew, `python3`
291
- // often points to the latest (e.g. 3.13) while python@3.12 is also installed
292
- // at /opt/homebrew/opt/python@3.12/bin/python3.12. Don't force the user to
293
- // reinstall just because the default changed.
294
- const pyProbes = [
295
- 'python3.12 --version',
296
- '/opt/homebrew/opt/python@3.12/bin/python3.12 --version',
297
- '/usr/local/opt/python@3.12/bin/python3.12 --version',
298
- 'python3 --version',
299
- ];
300
- for (const cmd of pyProbes) {
301
- try {
302
- const out = execSync(cmd, { encoding: 'utf-8', timeout: 3000 }).trim();
303
- const ver = out.replace('Python ', '');
304
- const parts = ver.split('.').map(Number);
305
- // Only accept as "ok" if this probe returned 3.12. Otherwise keep trying.
306
- if (parts[0] === 3 && parts[1] === 12) {
307
- currentPy = ver;
308
- pyStatus = 'ok';
309
- break;
310
- }
311
- // Remember the last-seen version for fallback reporting
312
- currentPy = ver;
313
- if (parts[0] === 3 && parts[1] >= 10 && parts[1] < 12)
314
- pyStatus = 'old';
315
- else if (parts[0] === 3 && parts[1] > 12)
316
- pyStatus = 'new';
317
- else
318
- pyStatus = 'missing';
319
- }
320
- catch { /* try next probe */ }
321
- }
322
- if (pyStatus === 'ok') {
323
- console.log(chalk.green(` ✓ Python ${currentPy} — you're good!`));
324
- console.log(chalk.gray(' Exam toolkit ready. Next: ') + chalk.bold.cyan('exam setup'));
325
- console.log();
326
- return;
327
- }
328
- if (pyStatus === 'old') {
329
- console.log(chalk.yellow(` ⚠ Python ${currentPy} — works, but 3.12 recommended`));
330
- }
331
- else if (pyStatus === 'new') {
332
- console.log(chalk.yellow(` ⚠ Python ${currentPy} — some packages (pwntools, scapy) lack wheels`));
333
- console.log(chalk.gray(' Downgrading to 3.12 is strongly recommended'));
334
- }
335
- else {
336
- console.log(chalk.red(' ✗ Python 3 not found'));
337
- }
338
- console.log();
339
- if (os === 'darwin') {
340
- console.log(chalk.bold.white(' macOS (Homebrew)'));
341
- console.log();
342
- console.log(chalk.green(' brew install python@3.12'));
343
- }
344
- else if (os === 'linux') {
345
- let distro = 'ubuntu';
346
- try {
347
- const release = execSync('cat /etc/os-release 2>/dev/null', { encoding: 'utf-8', timeout: 2000 });
348
- if (/fedora|rhel|centos/i.test(release))
349
- distro = 'fedora';
350
- else if (/arch|manjaro/i.test(release))
351
- distro = 'arch';
352
- else
353
- distro = 'ubuntu';
354
- }
355
- catch { }
356
- if (distro === 'ubuntu') {
357
- console.log(chalk.bold.white(' Ubuntu / Debian / Kali (deadsnakes PPA)'));
358
- console.log();
359
- console.log(chalk.gray(' Copy-paste this one-liner:'));
360
- console.log();
361
- console.log(chalk.green(' sudo add-apt-repository ppa:deadsnakes/ppa -y && \\'));
362
- console.log(chalk.green(' sudo apt update && \\'));
363
- console.log(chalk.green(' sudo apt install -y python3.12 python3.12-venv python3.12-distutils && \\'));
364
- console.log(chalk.green(' sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1'));
365
- }
366
- else if (distro === 'fedora') {
367
- console.log(chalk.bold.white(' Fedora / RHEL / CentOS'));
368
- console.log();
369
- console.log(chalk.green(' sudo dnf install -y python3.12 python3.12-pip'));
370
- }
371
- else if (distro === 'arch') {
372
- console.log(chalk.bold.white(' Arch / Manjaro (via pyenv)'));
373
- console.log();
374
- console.log(chalk.green(' sudo pacman -S pyenv && pyenv install 3.12 && pyenv global 3.12'));
375
- }
376
- }
377
- else if (os === 'win32') {
378
- console.log(chalk.bold.white(' Windows (WSL recommended)'));
379
- console.log();
380
- console.log(chalk.gray(' WSL + Ubuntu (best):'));
381
- console.log(chalk.green(' wsl --install'));
382
- console.log(chalk.gray(' Then inside Ubuntu, run the Ubuntu commands.'));
383
- console.log();
384
- console.log(chalk.gray(' Or native:'));
385
- console.log(chalk.green(' winget install Python.Python.3.12'));
386
- }
387
- else {
388
- console.log(chalk.gray(' https://www.python.org/downloads/'));
389
- }
390
- console.log();
391
- console.log(chalk.white(' After installing, verify:'));
392
- console.log(chalk.bold.cyan(' env python') + chalk.gray(' # re-check Python'));
393
- console.log(chalk.bold.cyan(' exam setup') + chalk.gray(' # install the 13 exam packages'));
394
- console.log();
395
- }
396
- function showStatus() {
397
- console.log();
398
- const os = platform();
399
- const pm = os === 'darwin' ? 'brew' : os === 'linux' ? 'apt' : 'winget';
400
- console.log(chalk.bold.white(' ICOA Competition Environment'));
401
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
402
- console.log();
403
- console.log(chalk.gray(' These tools power your CTF competition environment.'));
404
- console.log(chalk.gray(' Not all are required — here\'s what matters:'));
405
- console.log();
406
- console.log(chalk.green(' Essential') + chalk.gray(' pwntools, z3, requests, numpy'));
407
- console.log(chalk.gray(' You need these for most challenges'));
408
- console.log(chalk.yellow(' Recommended') + chalk.gray(' pycryptodome, beautifulsoup4, scapy, sympy'));
409
- console.log(chalk.gray(' Covers Web, Crypto, and Forensics'));
410
- console.log(chalk.gray(' Full (110) All tools for every category'));
411
- console.log();
412
- console.log(chalk.gray(' Missing tools? Run ') + chalk.bold.cyan('env setup') + chalk.gray(' to install everything.'));
413
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
414
- console.log();
415
- console.log(chalk.gray(' OS: ') + chalk.white(getOsInfo()));
416
- console.log(chalk.gray(' Node: ') + chalk.white(getNodeInfo()));
417
- console.log(chalk.gray(' Package: ') + chalk.white(pm));
418
- console.log(chalk.gray(' Target: ') + chalk.white(`Node ${NODE_EXACT} | Python ${PYTHON_EXACT}`));
419
- if (os === 'win32') {
420
- console.log();
421
- console.log(chalk.yellow(' Windows: recommend WSL (Ubuntu) for full CTF tool support'));
422
- console.log(chalk.gray(' Install WSL: ') + chalk.white('wsl --install'));
423
- console.log(chalk.gray(' Then run icoa inside WSL for 100% tool compatibility'));
424
- }
425
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
426
- // Node.js version check — >= 22.22.2
427
- const nodeVer = process.versions.node;
428
- const nodeParts = nodeVer.split('.').map(Number);
429
- const nodeOk = nodeParts[0] > 22 || (nodeParts[0] === 22 && nodeParts[1] > 22) || (nodeParts[0] === 22 && nodeParts[1] === 22 && nodeParts[2] >= 2);
430
- if (nodeOk) {
431
- console.log(chalk.green(` ✓ Node.js ${nodeVer}`) + chalk.gray(` (>= ${NODE_EXACT})`));
432
- }
433
- else {
434
- console.log(chalk.red(` ✗ Node.js ${nodeVer}`) + chalk.gray(` (>= ${NODE_EXACT} required)`));
435
- console.log(chalk.gray(' Install: nvm install 22 or visit https://nodejs.org/'));
436
- }
437
- // Python version check
438
- const pyVer = getPythonMajorMinor();
439
- const fullVer = getPythonFullVersion();
440
- if (fullVer === PYTHON_EXACT) {
441
- console.log(chalk.green(` ✓ Python ${fullVer}`) + chalk.gray(' (official)'));
442
- }
443
- else if (pyVer === '3.12') {
444
- console.log(chalk.yellow(` ~ Python ${fullVer}`) + chalk.gray(` (${PYTHON_EXACT} recommended, run env setup)`));
445
- }
446
- else if (pyVer) {
447
- console.log(chalk.yellow(` ~ Python ${fullVer}`) + chalk.gray(` (${PYTHON_EXACT} required, run env setup)`));
448
- }
449
- else {
450
- console.log(chalk.red(' ✗ Python 3 not found'));
451
- }
452
- console.log();
453
- let installed = 0;
454
- let missing = 0;
455
- let currentCategory = '';
456
- for (const tool of SYSTEM_TOOLS) {
457
- if (tool.category !== currentCategory) {
458
- currentCategory = tool.category;
459
- console.log(chalk.bold.gray(` ${currentCategory}`));
460
- }
461
- const ok = isInstalled(tool.check);
462
- const ver = ok ? getVersion(tool.name) : '';
463
- const verStr = ver ? chalk.gray(` (${ver})`) : '';
464
- if (ok) {
465
- console.log(chalk.green(` ✓ ${tool.name}`) + verStr);
466
- installed++;
467
- }
468
- else {
469
- console.log(chalk.red(` ✗ ${tool.name}`));
470
- missing++;
471
- }
472
- }
473
- currentCategory = '';
474
- const pipExe = os === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12' : os === 'win32' ? 'pip' : 'pip3';
475
- for (const lib of PYTHON_LIBS) {
476
- if (lib.category !== currentCategory) {
477
- currentCategory = lib.category;
478
- console.log(chalk.bold.gray(` ${currentCategory}`));
479
- }
480
- const ok = isInstalled(lib.check);
481
- if (ok) {
482
- // Get actual installed version
483
- let ver = '';
484
- for (const pip of [pipExe, 'pip3', 'pip']) {
485
- try {
486
- const pkgName = lib.name.replace('python-magic', 'python_magic');
487
- const out = execSync(`${pip} show ${pkgName}`, { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'ignore'] });
488
- const m = out.match(/Version:\s*(\S+)/);
489
- if (m) {
490
- ver = m[1];
491
- break;
492
- }
493
- }
494
- catch { /* try next */ }
495
- }
496
- console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(ver ? ` (${ver})` : ''));
497
- installed++;
498
- }
499
- else {
500
- console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(` → ${lib.install || 'latest'}`));
501
- missing++;
502
- }
503
- }
504
- const total = installed + missing;
505
- console.log();
506
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
507
- console.log(` ${chalk.green(`✓ ${installed}/${total}`)} ${missing > 0 ? chalk.red(`✗ ${missing} missing`) : chalk.green('All 110 ready!')}`);
508
- if (missing > 0) {
509
- console.log(chalk.gray(' Install everything: ') + chalk.white('env setup') + chalk.gray(' (~5 min, one-time)'));
510
- }
511
- console.log(chalk.gray(' You are back at the ') + chalk.cyan('icoa>') + chalk.gray(' prompt. ') + chalk.cyan('help') + chalk.gray(' for all commands.'));
512
- console.log();
513
- }
514
- async function installAll() {
515
- console.log();
516
- const os = platform();
517
- const pipFlag = os === 'darwin' || os === 'linux' ? '--break-system-packages' : '';
518
- console.log(chalk.bold.white(' ICOA Environment Setup'));
519
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
520
- console.log(chalk.gray(' This will install:'));
521
- console.log(chalk.white(' Python 3.12') + chalk.gray(' Runtime for CTF tools'));
522
- console.log(chalk.white(` ${PYTHON_LIBS.length} Python libraries`) + chalk.gray(' pwntools, z3, crypto...'));
523
- console.log(chalk.white(` ${SYSTEM_TOOLS.length} system tools`) + chalk.gray(' gcc, gdb, nmap, wireshark...'));
524
- console.log();
525
- console.log(chalk.gray(' Estimated: ~500 MB disk, 5-15 min (depends on network)'));
526
- console.log(chalk.gray(' Already installed tools will be skipped.'));
527
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
528
- console.log();
529
- // Node.js version check
530
- const nodeVer = process.versions.node;
531
- if (nodeVer === NODE_EXACT) {
532
- console.log(chalk.green(` ✓ Node.js ${NODE_EXACT}`));
533
- }
534
- else {
535
- console.log(chalk.yellow(` Node.js ${nodeVer} — installing ${NODE_EXACT}...`));
536
- try {
537
- if (os === 'darwin') {
538
- execSync(`brew install node@22`, { stdio: 'inherit' });
539
- }
540
- else if (os === 'linux') {
541
- execSync(`curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs`, { stdio: 'inherit' });
542
- }
543
- else {
544
- execSync(`winget install OpenJS.NodeJS.LTS --version ${NODE_EXACT}`, { stdio: 'inherit' });
545
- }
546
- console.log(chalk.green(` ✓ Node.js ${NODE_EXACT} installed`));
547
- console.log(chalk.gray(' Restart icoa to use the new version.'));
548
- }
549
- catch {
550
- console.log(chalk.yellow(` ~ Node.js upgrade skipped. Install manually: nvm install ${NODE_EXACT}`));
551
- }
552
- }
553
- console.log();
554
- // Python version check — install 3.12.13 if needed
555
- const pyVer = getPythonMajorMinor();
556
- const currentFullVer = getPythonFullVersion();
557
- if (currentFullVer === PYTHON_EXACT) {
558
- console.log(chalk.green(` ✓ Python ${PYTHON_EXACT}`));
559
- console.log();
560
- }
561
- else {
562
- console.log(chalk.yellow(` Python ${currentFullVer || 'not found'} — installing Python ${PYTHON_EXACT}...`));
563
- try {
564
- if (os === 'darwin') {
565
- execSync('brew install python@3.12', { stdio: 'inherit' });
566
- // Link python3.12 as default python3
567
- try {
568
- execSync('brew link --overwrite python@3.12', { stdio: 'ignore' });
569
- }
570
- catch { /* ok */ }
571
- console.log(chalk.green(' ✓ Python 3.12 installed'));
572
- console.log(chalk.gray(' Use: /opt/homebrew/opt/python@3.12/bin/python3.12'));
573
- console.log(chalk.gray(' Or: brew link --overwrite python@3.12'));
574
- }
575
- else if (os === 'linux') {
576
- console.log(chalk.gray(` Building Python ${PYTHON_EXACT} from source...`));
577
- // Install build dependencies
578
- execSync('sudo apt-get update && sudo apt-get install -y build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev libffi-dev tk-dev curl', { stdio: 'inherit' });
579
- // Download and build
580
- execSync(`curl -sS https://www.python.org/ftp/python/${PYTHON_EXACT}/Python-${PYTHON_EXACT}.tgz -o /tmp/Python-${PYTHON_EXACT}.tgz`, { stdio: 'inherit' });
581
- execSync(`cd /tmp && tar xzf Python-${PYTHON_EXACT}.tgz && cd Python-${PYTHON_EXACT} && ./configure --prefix=/usr/local --enable-optimizations 2>&1 | tail -1 && make -j$(nproc) 2>&1 | tail -1 && sudo make altinstall`, { stdio: 'inherit', timeout: 600000 });
582
- // Install pip
583
- try {
584
- execSync('curl -sS https://bootstrap.pypa.io/get-pip.py | sudo /usr/local/bin/python3.12', { stdio: 'inherit' });
585
- }
586
- catch { /* ok */ }
587
- // Set as default
588
- try {
589
- execSync('sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.12 2', { stdio: 'ignore' });
590
- execSync('sudo update-alternatives --set python3 /usr/local/bin/python3.12', { stdio: 'ignore' });
591
- }
592
- catch { /* ok */ }
593
- console.log(chalk.green(` ✓ Python ${PYTHON_EXACT} installed`));
594
- }
595
- else {
596
- // Windows: try winget first, then choco
597
- try {
598
- execSync('winget install Python.Python.3.12 --accept-package-agreements --accept-source-agreements', { stdio: 'inherit' });
599
- }
600
- catch {
601
- execSync('choco install -y python312', { stdio: 'inherit' });
602
- }
603
- console.log(chalk.green(' ✓ Python 3.12 installed'));
604
- }
605
- }
606
- catch {
607
- console.log(chalk.red(' ✗ Failed to install Python 3.12'));
608
- const hint = os === 'darwin' ? 'brew install python@3.12' : os === 'linux' ? 'sudo apt install python3.12' : 'winget install Python.Python.3.12';
609
- console.log(chalk.gray(` Manual install: ${hint}`));
610
- }
611
- console.log();
612
- }
613
- // Windows: recommend WSL instead of installing tools natively
614
- if (os === 'win32') {
615
- console.log(chalk.yellow(' Windows: Most CTF tools require Linux. Recommended:'));
616
- console.log(chalk.white(' wsl --install'));
617
- console.log(chalk.gray(' Then run icoa inside WSL Ubuntu for full tool support.'));
618
- console.log();
619
- }
620
- // Install system tools via brew (macOS) / apt (Linux)
621
- const missingSystem = [];
622
- for (const tool of SYSTEM_TOOLS) {
623
- if (!isInstalled(tool.check)) {
624
- const pkg = os === 'darwin' ? tool.brew : os === 'linux' ? tool.apt : tool.choco;
625
- if (pkg)
626
- missingSystem.push(tool);
627
- }
628
- }
629
- if (missingSystem.length > 0 && os !== 'win32') {
630
- const pmName = os === 'darwin' ? 'brew' : 'apt';
631
- console.log(chalk.bold.white(` System Tools via ${pmName} (${missingSystem.length} missing)`));
632
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
633
- for (const tool of missingSystem) {
634
- const pkg = os === 'darwin' ? tool.brew : os === 'linux' ? tool.apt : tool.choco;
635
- process.stdout.write(chalk.gray(` ⏳ ${tool.name}...`));
636
- try {
637
- let cmd;
638
- if (os === 'darwin')
639
- cmd = `brew install ${pkg}`;
640
- else if (os === 'linux')
641
- cmd = `sudo apt-get install -y ${pkg}`;
642
- else
643
- cmd = `choco install -y ${pkg}`;
644
- execSync(cmd, { stdio: 'ignore' });
645
- process.stdout.write('\r');
646
- console.log(chalk.green(` ✓ ${tool.name}`));
647
- }
648
- catch {
649
- process.stdout.write('\r');
650
- console.log(chalk.red(` ✗ ${tool.name}`) + chalk.gray(` (${pmName} install ${pkg})`));
651
- }
652
- }
653
- console.log();
654
- }
655
- // Find the correct pip for Python 3.12
656
- let pipCmd = 'pip3';
657
- if (os === 'darwin') {
658
- // Prefer brew Python 3.12 pip over conda/system pip
659
- const brewPip = '/opt/homebrew/opt/python@3.12/bin/pip3.12';
660
- try {
661
- execSync(`${brewPip} --version`, { stdio: 'ignore' });
662
- pipCmd = brewPip;
663
- console.log(chalk.gray(` Using: ${brewPip}`));
664
- }
665
- catch {
666
- // Try generic pip3.12
667
- try {
668
- execSync('pip3.12 --version', { stdio: 'ignore' });
669
- pipCmd = 'pip3.12';
670
- }
671
- catch { /* fall back to pip3 */ }
672
- }
673
- }
674
- else if (os === 'linux') {
675
- try {
676
- execSync('pip3.12 --version', { stdio: 'ignore' });
677
- pipCmd = 'pip3.12';
678
- }
679
- catch { /* fall back to pip3 */ }
680
- }
681
- else if (os === 'win32') {
682
- pipCmd = 'pip';
683
- }
684
- // Pre-install system dependencies for packages that need them
685
- if (os === 'darwin') {
686
- console.log(chalk.gray(' Installing build dependencies...'));
687
- try {
688
- execSync('brew install gmp mpfr libmpc libmagic', { stdio: 'ignore' });
689
- console.log(chalk.green(' ✓ Build dependencies ready (gmp, mpfr, libmpc, libmagic)'));
690
- }
691
- catch { /* some may already exist */ }
692
- }
693
- else if (os === 'linux') {
694
- try {
695
- execSync('sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev libmagic1', { stdio: 'ignore' });
696
- }
697
- catch { /* ignore */ }
698
- }
699
- console.log();
700
- // Build environment for native extensions (gmpy2 etc.)
701
- const buildEnv = { ...process.env };
702
- if (os === 'darwin') {
703
- buildEnv['CFLAGS'] = `-I/opt/homebrew/include ${buildEnv['CFLAGS'] || ''}`.trim();
704
- buildEnv['LDFLAGS'] = `-L/opt/homebrew/lib ${buildEnv['LDFLAGS'] || ''}`.trim();
705
- buildEnv['C_INCLUDE_PATH'] = `/opt/homebrew/include:${buildEnv['C_INCLUDE_PATH'] || ''}`;
706
- buildEnv['LIBRARY_PATH'] = `/opt/homebrew/lib:${buildEnv['LIBRARY_PATH'] || ''}`;
707
- }
708
- // Install Python libraries
709
- let pipInstalled = 0;
710
- let pipFailed = 0;
711
- console.log(chalk.bold.white(` Python Libraries (${PYTHON_LIBS.length} packages)`));
712
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
713
- for (const lib of PYTHON_LIBS) {
714
- if (!lib.install)
715
- continue;
716
- if (isInstalled(lib.check)) {
717
- console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(' (installed)'));
718
- pipInstalled++;
719
- continue;
720
- }
721
- process.stdout.write(chalk.gray(` ⏳ ${lib.name}...`));
722
- try {
723
- execSync(`${pipCmd} install ${pipFlag} ${lib.install}`, { stdio: 'ignore', env: buildEnv });
724
- process.stdout.write('\r');
725
- console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(` (${lib.install})`));
726
- pipInstalled++;
727
- }
728
- catch {
729
- process.stdout.write('\r');
730
- console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(' (failed)'));
731
- pipFailed++;
732
- }
733
- }
734
- console.log();
735
- console.log(chalk.gray(' ─────────────────────────────────────────────'));
736
- console.log(` ${chalk.green(`✓ ${pipInstalled} installed`)} ${pipFailed > 0 ? chalk.red(`✗ ${pipFailed} failed`) : chalk.green('All ready!')}`);
737
- console.log();
738
- }
1
+ import chalk from"chalk";import{execSync as e}from"node:child_process";import{platform as o}from"node:os";const n="3.12.13",t="22.22.2",c=[{name:"pwntools",check:'python3 -c "import pwn"',install:"pwntools==4.12.0",category:"CTF Core"},{name:"pycryptodome",check:'python3 -c "import Crypto"',install:"pycryptodome==3.20.0",category:"CTF Core"},{name:"z3-solver",check:'python3 -c "import z3"',install:"z3-solver==4.12.6",category:"CTF Core"},{name:"angr",check:'python3 -c "import angr"',install:"angr",category:"CTF Core"},{name:"requests",check:'python3 -c "import requests"',install:"requests==2.31.0",category:"Web & Network"},{name:"beautifulsoup4",check:'python3 -c "import bs4"',install:"beautifulsoup4==4.12.3",category:"Web & Network"},{name:"flask",check:'python3 -c "import flask"',install:"flask==3.0.0",category:"Web & Network"},{name:"scapy",check:'python3 -c "import scapy"',install:"scapy==2.5.0",category:"Web & Network"},{name:"paramiko",check:'python3 -c "import paramiko"',install:"paramiko==3.4.0",category:"Web & Network"},{name:"sympy",check:'python3 -c "import sympy"',install:"sympy==1.12",category:"Crypto & Math"},{name:"gmpy2",check:"darwin"===process.platform?'/opt/homebrew/opt/python@3.12/bin/python3.12 -c "import gmpy2"':'python3 -c "import gmpy2"',install:"gmpy2>=2.2.0",category:"Crypto & Math"},{name:"cryptography",check:'python3 -c "import cryptography"',install:"cryptography==42.0.0",category:"Crypto & Math"},{name:"capstone",check:'python3 -c "import capstone"',install:"capstone==5.0.1",category:"Binary & RE"},{name:"ropper",check:'python3 -c "import ropper"',install:"ropper==1.13.8",category:"Binary & RE"},{name:"ROPgadget",check:"which ROPgadget",install:"ROPgadget==7.4",category:"Binary & RE"},{name:"pefile",check:'python3 -c "import pefile"',install:"pefile==2023.2.7",category:"Binary & RE"},{name:"pillow",check:'python3 -c "import PIL"',install:"pillow==10.2.0",category:"Data & Forensics"},{name:"numpy",check:'python3 -c "import numpy"',install:"numpy==1.26.4",category:"Data & Forensics"},{name:"python-magic",check:'python3 -c "import magic"',install:"python-magic==0.4.27",category:"Data & Forensics"},{name:"yara-python",check:'python3 -c "import yara"',install:"yara-python==4.5.0",category:"Data & Forensics"},{name:"sqlmap",check:"which sqlmap",install:"sqlmap",category:"Security Tools"},{name:"ipython",check:"which ipython3 || which ipython",install:"ipython",category:"Security Tools"},{name:"uncompyle6",check:'python3 -c "import uncompyle6"',install:"uncompyle6==3.9.1",category:"Security Tools"},{name:"volatility3",check:'python3 -c "import volatility3"',install:"volatility3",category:"Security Tools"},{name:"pyserial",check:'python3 -c "import serial"',install:"pyserial==3.5",category:"Security Tools"}],r="win32"===process.platform,a=(e,o)=>r?o||`where ${e}`:`which ${e}`,s=[{name:"vim",check:a("vim"),brew:"vim",apt:"vim",choco:"vim",category:"Editors & Terminal"},{name:"nano",check:a("nano"),brew:"nano",apt:"nano",choco:"nano",category:"Editors & Terminal"},{name:"tmux",check:a("tmux"),brew:"tmux",apt:"tmux",category:"Editors & Terminal"},{name:"screen",check:a("screen"),brew:"screen",apt:"screen",category:"Editors & Terminal"},{name:"less",check:a("less"),category:"Editors & Terminal"},{name:"gcc",check:a("gcc"),brew:"gcc",apt:"gcc",choco:"mingw",category:"Compilers & Build"},{name:"g++",check:a("g++"),brew:"gcc",apt:"g++",choco:"mingw",category:"Compilers & Build"},{name:"make",check:a("make"),brew:"make",apt:"make",choco:"make",category:"Compilers & Build"},{name:"nasm",check:a("nasm"),brew:"nasm",apt:"nasm",choco:"nasm",category:"Compilers & Build"},{name:"cmake",check:a("cmake"),brew:"cmake",apt:"cmake",choco:"cmake",category:"Compilers & Build"},{name:"as",check:a("as"),category:"Compilers & Build"},{name:"ld",check:a("ld"),category:"Compilers & Build"},{name:"pkg-config",check:a("pkg-config"),brew:"pkg-config",apt:"pkg-config",category:"Compilers & Build"},{name:"python3",check:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/python3.12 --version":r?"python --version":"python3 --version",brew:"python@3.12",apt:"python3",choco:"python312",category:"Python Runtime"},{name:"pip3",check:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/pip3.12 --version":r?"pip --version":"pip3 --version",category:"Python Runtime"},{name:"python3-venv",check:r?'python -c "import venv"':'python3 -c "import venv"',apt:"python3-venv",category:"Python Runtime"},{name:"curl",check:a("curl"),brew:"curl",apt:"curl",choco:"curl",category:"Networking"},{name:"wget",check:a("wget"),brew:"wget",apt:"wget",choco:"wget",category:"Networking"},{name:"nc",check:a("nc","where ncat"),brew:"netcat",apt:"netcat-openbsd",choco:"nmap",category:"Networking"},{name:"socat",check:a("socat"),brew:"socat",apt:"socat",category:"Networking"},{name:"nmap",check:a("nmap"),brew:"nmap",apt:"nmap",choco:"nmap",category:"Networking"},{name:"ssh",check:a("ssh"),apt:"openssh-client",category:"Networking"},{name:"dig",check:a("dig"),brew:"bind",apt:"dnsutils",category:"Networking"},{name:"whois",check:a("whois"),brew:"whois",apt:"whois",choco:"whois",category:"Networking"},{name:"ping",check:a("ping"),apt:"iputils-ping",category:"Networking"},{name:"traceroute",check:a("traceroute","where tracert"),brew:"traceroute",apt:"traceroute",category:"Networking"},{name:"tcpdump",check:a("tcpdump"),brew:"tcpdump",apt:"tcpdump",category:"Networking"},{name:"tshark",check:a("tshark"),brew:"wireshark",apt:"tshark",choco:"wireshark",category:"Networking"},{name:"gdb",check:a("gdb"),brew:"gdb",apt:"gdb",choco:"mingw",category:"Debuggers"},..."darwin"!==process.platform?[{name:"ltrace",check:a("ltrace"),apt:"ltrace",category:"Debuggers"},{name:"strace",check:a("strace"),apt:"strace",category:"Debuggers"}]:[],{name:"objdump",check:a("objdump"),category:"Debuggers"},..."darwin"!==process.platform?[{name:"readelf",check:a("readelf"),category:"Debuggers"}]:[],{name:"radare2",check:a("r2"),brew:"radare2",apt:"radare2",choco:"radare2",category:"Reverse Engineering"},{name:"rabin2",check:a("rabin2"),category:"Reverse Engineering"},{name:"upx",check:a("upx"),brew:"upx",apt:"upx",choco:"upx",category:"Reverse Engineering"},{name:"strings",check:a("strings"),category:"Reverse Engineering"},{name:"binwalk",check:a("binwalk"),brew:"binwalk",apt:"binwalk",category:"Forensics"},..."darwin"!==process.platform?[{name:"foremost",check:a("foremost"),apt:"foremost",category:"Forensics"}]:[],{name:"exiftool",check:a("exiftool"),brew:"exiftool",apt:"exiftool",choco:"exiftool",category:"Forensics"},..."darwin"!==process.platform?[{name:"steghide",check:a("steghide"),apt:"steghide",category:"Forensics"}]:[],{name:"file",check:a("file"),category:"Forensics"},{name:"xxd",check:a("xxd"),brew:"vim",apt:"xxd",category:"Forensics"},{name:"pdftotext",check:a("pdftotext"),brew:"poppler",apt:"poppler-utils",category:"Forensics"},{name:"pngcheck",check:a("pngcheck"),brew:"pngcheck",apt:"pngcheck",category:"Forensics"},{name:"sleuthkit",check:a("mmls"),brew:"sleuthkit",apt:"sleuthkit",choco:"sleuthkit",category:"Forensics"},{name:"john",check:a("john"),brew:"john",apt:"john",choco:"john",category:"Crypto & Password"},{name:"hashcat",check:a("hashcat"),brew:"hashcat",apt:"hashcat",choco:"hashcat",category:"Crypto & Password"},{name:"openssl",check:a("openssl"),category:"Crypto & Password"},{name:"gpg",check:a("gpg"),brew:"gnupg",apt:"gpg",choco:"gnupg",category:"Crypto & Password"},{name:"jq",check:a("jq"),brew:"jq",apt:"jq",choco:"jq",category:"Data Processing"},{name:"sqlite3",check:a("sqlite3"),brew:"sqlite",apt:"sqlite3",choco:"sqlite",category:"Data Processing"},{name:"base64",check:a("base64"),category:"Data Processing"},{name:"hexdump",check:a("hexdump"),category:"Data Processing"},{name:"od",check:a("od"),category:"Data Processing"},{name:"sort",check:a("sort"),category:"Data Processing"},{name:"uniq",check:a("uniq"),category:"Data Processing"},{name:"wc",check:a("wc"),category:"Data Processing"},{name:"unzip",check:a("unzip"),brew:"unzip",apt:"unzip",category:"Archive"},{name:"zip",check:a("zip"),brew:"zip",apt:"zip",category:"Archive"},{name:"tar",check:a("tar"),category:"Archive"},{name:"gzip",check:a("gzip"),category:"Archive"},{name:"bzip2",check:a("bzip2"),category:"Archive"},{name:"xz",check:a("xz"),brew:"xz",apt:"xz-utils",category:"Archive"},{name:"cat",check:a("cat"),category:"Core Unix"},{name:"grep",check:a("grep"),category:"Core Unix"},{name:"sed",check:a("sed"),category:"Core Unix"},{name:"awk",check:a("awk"),category:"Core Unix"},{name:"find",check:a("find"),category:"Core Unix"},{name:"head",check:a("head"),category:"Core Unix"},{name:"tail",check:a("tail"),category:"Core Unix"},{name:"diff",check:a("diff"),category:"Core Unix"},{name:"patch",check:a("patch"),category:"Core Unix"},{name:"chmod",check:a("chmod"),category:"Core Unix"},{name:"chown",check:a("chown"),category:"Core Unix"},{name:"ln",check:a("ln"),category:"Core Unix"},{name:"cp",check:a("cp"),category:"Core Unix"},{name:"mv",check:a("mv"),category:"Core Unix"},{name:"mkdir",check:a("mkdir"),category:"Core Unix"},{name:"rm",check:a("rm"),category:"Core Unix"},{name:"git",check:a("git"),brew:"git",apt:"git",choco:"git",category:"Git & Docker"},{name:"docker",check:a("docker"),brew:"--cask docker",choco:"docker-desktop",category:"Git & Docker"}];function i(o){try{return e(o,{stdio:"ignore"}),!0}catch{return!1}}function l(o){const n={python3:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/python3.12 --version":"python3 --version",pip3:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/pip3.12 --version":"pip3 --version",gcc:"gcc --version","g++":"g++ --version",make:"make --version",nasm:"nasm --version",cmake:"cmake --version",vim:"vim --version",nano:"nano --version",tmux:"tmux -V",screen:"screen --version",curl:"curl --version",wget:"wget --version",nmap:"nmap --version",ssh:"ssh -V",socat:"socat -V",gdb:"gdb --version",radare2:"r2 -v",upx:"upx --version",binwalk:"binwalk --help",exiftool:"exiftool -ver",john:"john --help",hashcat:"hashcat --version",openssl:"openssl version",gpg:"gpg --version",jq:"jq --version",sqlite3:"sqlite3 --version",git:"git --version",docker:"docker --version",tshark:"tshark --version",tcpdump:"tcpdump --version",pdftotext:"pdftotext -v",pngcheck:"pngcheck 2>&1"}[o];if(!n)return"";try{const o=e(n+" 2>&1",{encoding:"utf-8",timeout:3e3}).trim().match(/(\d+\.\d+[\.\d]*)/);return o?.[1]||""}catch{}return""}function g(){if("darwin"===process.platform)try{return e("/opt/homebrew/opt/python@3.12/bin/python3.12 -c \"import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')\"",{encoding:"utf-8"}).trim()}catch{}try{return e("python3 -c \"import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')\"",{encoding:"utf-8"}).trim()}catch{return""}}function p(){if("darwin"===process.platform)try{return e("/opt/homebrew/opt/python@3.12/bin/python3.12 --version",{encoding:"utf-8"}).trim().replace("Python ","")}catch{}try{return e("python3 --version",{encoding:"utf-8"}).trim().replace("Python ","")}catch{return""}}export function registerEnvCommand(r){const a=r.command("env").description("Manage competition environment");a.command("status").alias("check").description("Check all 110 tools").action(()=>h()),a.command("setup").description("Install all Python libraries + system tools").action(async()=>{await async function(){console.log();const r=o(),a="darwin"===r||"linux"===r?"--break-system-packages":"";console.log(chalk.bold.white(" ICOA Environment Setup")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(chalk.gray(" This will install:")),console.log(chalk.white(" Python 3.12")+chalk.gray(" Runtime for CTF tools")),console.log(chalk.white(` ${c.length} Python libraries`)+chalk.gray(" pwntools, z3, crypto...")),console.log(chalk.white(` ${s.length} system tools`)+chalk.gray(" gcc, gdb, nmap, wireshark...")),console.log(),console.log(chalk.gray(" Estimated: ~500 MB disk, 5-15 min (depends on network)")),console.log(chalk.gray(" Already installed tools will be skipped.")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log();const l=process.versions.node;if(l===t)console.log(chalk.green(` ✓ Node.js ${t}`));else{console.log(chalk.yellow(` Node.js ${l} — installing ${t}...`));try{e("darwin"===r?"brew install node@22":"linux"===r?"curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs":`winget install OpenJS.NodeJS.LTS --version ${t}`,{stdio:"inherit"}),console.log(chalk.green(` ✓ Node.js ${t} installed`)),console.log(chalk.gray(" Restart icoa to use the new version."))}catch{console.log(chalk.yellow(` ~ Node.js upgrade skipped. Install manually: nvm install ${t}`))}}console.log(),g();const h=p();if(h===n)console.log(chalk.green(` ✓ Python ${n}`)),console.log();else{console.log(chalk.yellow(` Python ${h||"not found"} — installing Python ${n}...`));try{if("darwin"===r){e("brew install python@3.12",{stdio:"inherit"});try{e("brew link --overwrite python@3.12",{stdio:"ignore"})}catch{}console.log(chalk.green(" ✓ Python 3.12 installed")),console.log(chalk.gray(" Use: /opt/homebrew/opt/python@3.12/bin/python3.12")),console.log(chalk.gray(" Or: brew link --overwrite python@3.12"))}else if("linux"===r){console.log(chalk.gray(` Building Python ${n} from source...`)),e("sudo apt-get update && sudo apt-get install -y build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev libffi-dev tk-dev curl",{stdio:"inherit"}),e(`curl -sS https://www.python.org/ftp/python/${n}/Python-${n}.tgz -o /tmp/Python-${n}.tgz`,{stdio:"inherit"}),e(`cd /tmp && tar xzf Python-${n}.tgz && cd Python-${n} && ./configure --prefix=/usr/local --enable-optimizations 2>&1 | tail -1 && make -j$(nproc) 2>&1 | tail -1 && sudo make altinstall`,{stdio:"inherit",timeout:6e5});try{e("curl -sS https://bootstrap.pypa.io/get-pip.py | sudo /usr/local/bin/python3.12",{stdio:"inherit"})}catch{}try{e("sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.12 2",{stdio:"ignore"}),e("sudo update-alternatives --set python3 /usr/local/bin/python3.12",{stdio:"ignore"})}catch{}console.log(chalk.green(` ✓ Python ${n} installed`))}else{try{e("winget install Python.Python.3.12 --accept-package-agreements --accept-source-agreements",{stdio:"inherit"})}catch{e("choco install -y python312",{stdio:"inherit"})}console.log(chalk.green(" ✓ Python 3.12 installed"))}}catch{console.log(chalk.red(" ✗ Failed to install Python 3.12"));const e="darwin"===r?"brew install python@3.12":"linux"===r?"sudo apt install python3.12":"winget install Python.Python.3.12";console.log(chalk.gray(` Manual install: ${e}`))}console.log()}"win32"===r&&(console.log(chalk.yellow(" Windows: Most CTF tools require Linux. Recommended:")),console.log(chalk.white(" wsl --install")),console.log(chalk.gray(" Then run icoa inside WSL Ubuntu for full tool support.")),console.log());const y=[];for(const e of s)i(e.check)||("darwin"===r?e.brew:"linux"===r?e.apt:e.choco)&&y.push(e);if(y.length>0&&"win32"!==r){const o="darwin"===r?"brew":"apt";console.log(chalk.bold.white(` System Tools via ${o} (${y.length} missing)`)),console.log(chalk.gray(" ─────────────────────────────────────────────"));for(const n of y){const t="darwin"===r?n.brew:"linux"===r?n.apt:n.choco;process.stdout.write(chalk.gray(` ⏳ ${n.name}...`));try{let o;o="darwin"===r?`brew install ${t}`:"linux"===r?`sudo apt-get install -y ${t}`:`choco install -y ${t}`,e(o,{stdio:"ignore"}),process.stdout.write("\r"),console.log(chalk.green(` ✓ ${n.name}`))}catch{process.stdout.write("\r"),console.log(chalk.red(` ✗ ${n.name}`)+chalk.gray(` (${o} install ${t})`))}}console.log()}let m="pip3";if("darwin"===r){const o="/opt/homebrew/opt/python@3.12/bin/pip3.12";try{e(`${o} --version`,{stdio:"ignore"}),m=o,console.log(chalk.gray(` Using: ${o}`))}catch{try{e("pip3.12 --version",{stdio:"ignore"}),m="pip3.12"}catch{}}}else if("linux"===r)try{e("pip3.12 --version",{stdio:"ignore"}),m="pip3.12"}catch{}else"win32"===r&&(m="pip");if("darwin"===r){console.log(chalk.gray(" Installing build dependencies..."));try{e("brew install gmp mpfr libmpc libmagic",{stdio:"ignore"}),console.log(chalk.green(" ✓ Build dependencies ready (gmp, mpfr, libmpc, libmagic)"))}catch{}}else if("linux"===r)try{e("sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev libmagic1",{stdio:"ignore"})}catch{}console.log();const d={...process.env};"darwin"===r&&(d.CFLAGS=`-I/opt/homebrew/include ${d.CFLAGS||""}`.trim(),d.LDFLAGS=`-L/opt/homebrew/lib ${d.LDFLAGS||""}`.trim(),d.C_INCLUDE_PATH=`/opt/homebrew/include:${d.C_INCLUDE_PATH||""}`,d.LIBRARY_PATH=`/opt/homebrew/lib:${d.LIBRARY_PATH||""}`);let u=0,w=0;console.log(chalk.bold.white(` Python Libraries (${c.length} packages)`)),console.log(chalk.gray(" ─────────────────────────────────────────────"));for(const o of c)if(o.install)if(i(o.check))console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (installed)")),u++;else{process.stdout.write(chalk.gray(` ⏳ ${o.name}...`));try{e(`${m} install ${a} ${o.install}`,{stdio:"ignore",env:d}),process.stdout.write("\r"),console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(` (${o.install})`)),u++}catch{process.stdout.write("\r"),console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(" (failed)")),w++}}console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${u} installed`)} ${w>0?chalk.red(`✗ ${w} failed`):chalk.green("All ready!")}`),console.log()}()}),a.command("python").description("Show Python 3.12 install guide for your platform").action(()=>function(){const n=o();console.log(),console.log(chalk.bold.white(" Python 3.12 — Installation Guide")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log();let t="",c="missing";const r=["python3.12 --version","/opt/homebrew/opt/python@3.12/bin/python3.12 --version","/usr/local/opt/python@3.12/bin/python3.12 --version","python3 --version"];for(const o of r)try{const n=e(o,{encoding:"utf-8",timeout:3e3}).trim().replace("Python ",""),r=n.split(".").map(Number);if(3===r[0]&&12===r[1]){t=n,c="ok";break}t=n,c=3===r[0]&&r[1]>=10&&r[1]<12?"old":3===r[0]&&r[1]>12?"new":"missing"}catch{}if("ok"===c)return console.log(chalk.green(` ✓ Python ${t} — you're good!`)),console.log(chalk.gray(" Exam toolkit ready. Next: ")+chalk.bold.cyan("exam setup")),void console.log();if("old"===c?console.log(chalk.yellow(` ⚠ Python ${t} — works, but 3.12 recommended`)):"new"===c?(console.log(chalk.yellow(` ⚠ Python ${t} — some packages (pwntools, scapy) lack wheels`)),console.log(chalk.gray(" Downgrading to 3.12 is strongly recommended"))):console.log(chalk.red(" ✗ Python 3 not found")),console.log(),"darwin"===n)console.log(chalk.bold.white(" macOS (Homebrew)")),console.log(),console.log(chalk.green(" brew install python@3.12"));else if("linux"===n){let o="ubuntu";try{const n=e("cat /etc/os-release 2>/dev/null",{encoding:"utf-8",timeout:2e3});o=/fedora|rhel|centos/i.test(n)?"fedora":/arch|manjaro/i.test(n)?"arch":"ubuntu"}catch{}"ubuntu"===o?(console.log(chalk.bold.white(" Ubuntu / Debian / Kali (deadsnakes PPA)")),console.log(),console.log(chalk.gray(" Copy-paste this one-liner:")),console.log(),console.log(chalk.green(" sudo add-apt-repository ppa:deadsnakes/ppa -y && \\")),console.log(chalk.green(" sudo apt update && \\")),console.log(chalk.green(" sudo apt install -y python3.12 python3.12-venv python3.12-distutils && \\")),console.log(chalk.green(" sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1"))):"fedora"===o?(console.log(chalk.bold.white(" Fedora / RHEL / CentOS")),console.log(),console.log(chalk.green(" sudo dnf install -y python3.12 python3.12-pip"))):"arch"===o&&(console.log(chalk.bold.white(" Arch / Manjaro (via pyenv)")),console.log(),console.log(chalk.green(" sudo pacman -S pyenv && pyenv install 3.12 && pyenv global 3.12")))}else"win32"===n?(console.log(chalk.bold.white(" Windows (WSL recommended)")),console.log(),console.log(chalk.gray(" WSL + Ubuntu (best):")),console.log(chalk.green(" wsl --install")),console.log(chalk.gray(" Then inside Ubuntu, run the Ubuntu commands.")),console.log(),console.log(chalk.gray(" Or native:")),console.log(chalk.green(" winget install Python.Python.3.12"))):console.log(chalk.gray(" https://www.python.org/downloads/"));console.log(),console.log(chalk.white(" After installing, verify:")),console.log(chalk.bold.cyan(" env python")+chalk.gray(" # re-check Python")),console.log(chalk.bold.cyan(" exam setup")+chalk.gray(" # install the 13 exam packages")),console.log()}()),a.action(()=>h())}function h(){console.log();const r=o(),a="darwin"===r?"brew":"linux"===r?"apt":"winget";console.log(chalk.bold.white(" ICOA Competition Environment")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),console.log(chalk.gray(" These tools power your CTF competition environment.")),console.log(chalk.gray(" Not all are required — here's what matters:")),console.log(),console.log(chalk.green(" Essential")+chalk.gray(" pwntools, z3, requests, numpy")),console.log(chalk.gray(" You need these for most challenges")),console.log(chalk.yellow(" Recommended")+chalk.gray(" pycryptodome, beautifulsoup4, scapy, sympy")),console.log(chalk.gray(" Covers Web, Crypto, and Forensics")),console.log(chalk.gray(" Full (110) All tools for every category")),console.log(),console.log(chalk.gray(" Missing tools? Run ")+chalk.bold.cyan("env setup")+chalk.gray(" to install everything.")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),console.log(chalk.gray(" OS: ")+chalk.white(function(){const n=o();try{if("darwin"===n)return`macOS ${e("sw_vers -productVersion",{encoding:"utf-8"}).trim()} (${e("uname -m",{encoding:"utf-8"}).trim()})`;if("linux"===n)try{const o=e("cat /etc/os-release | grep PRETTY_NAME",{encoding:"utf-8"}).match(/PRETTY_NAME="(.+)"/),n=e("uname -m",{encoding:"utf-8"}).trim();return o?`${o[1]} (${n})`:`Linux (${n})`}catch{return"Linux"}else if("win32"===n)return e("ver",{encoding:"utf-8"}).trim()||"Windows"}catch{}return n}())),console.log(chalk.gray(" Node: ")+chalk.white(`Node.js ${process.version}`)),console.log(chalk.gray(" Package: ")+chalk.white(a)),console.log(chalk.gray(" Target: ")+chalk.white(`Node ${t} | Python ${n}`)),"win32"===r&&(console.log(),console.log(chalk.yellow(" Windows: recommend WSL (Ubuntu) for full CTF tool support")),console.log(chalk.gray(" Install WSL: ")+chalk.white("wsl --install")),console.log(chalk.gray(" Then run icoa inside WSL for 100% tool compatibility"))),console.log(chalk.gray(" ─────────────────────────────────────────────"));const h=process.versions.node,y=h.split(".").map(Number);y[0]>22||22===y[0]&&y[1]>22||22===y[0]&&22===y[1]&&y[2]>=2?console.log(chalk.green(` ✓ Node.js ${h}`)+chalk.gray(` (>= ${t})`)):(console.log(chalk.red(` ✗ Node.js ${h}`)+chalk.gray(` (>= ${t} required)`)),console.log(chalk.gray(" Install: nvm install 22 or visit https://nodejs.org/")));const m=g(),d=p();d===n?console.log(chalk.green(` ✓ Python ${d}`)+chalk.gray(" (official)")):"3.12"===m?console.log(chalk.yellow(` ~ Python ${d}`)+chalk.gray(` (${n} recommended, run env setup)`)):m?console.log(chalk.yellow(` ~ Python ${d}`)+chalk.gray(` (${n} required, run env setup)`)):console.log(chalk.red(" ✗ Python 3 not found")),console.log();let u=0,w=0,k="";for(const e of s){e.category!==k&&(k=e.category,console.log(chalk.bold.gray(` ${k}`)));const o=i(e.check),n=o?l(e.name):"",t=n?chalk.gray(` (${n})`):"";o?(console.log(chalk.green(` ✓ ${e.name}`)+t),u++):(console.log(chalk.red(` ✗ ${e.name}`)),w++)}k="";const b="darwin"===r?"/opt/homebrew/opt/python@3.12/bin/pip3.12":"win32"===r?"pip":"pip3";for(const o of c)if(o.category!==k&&(k=o.category,console.log(chalk.bold.gray(` ${k}`))),i(o.check)){let n="";for(const t of[b,"pip3","pip"])try{const c=o.name.replace("python-magic","python_magic"),r=e(`${t} show ${c}`,{encoding:"utf-8",timeout:3e3,stdio:["pipe","pipe","ignore"]}).match(/Version:\s*(\S+)/);if(r){n=r[1];break}}catch{}console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(n?` (${n})`:"")),u++}else console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` → ${o.install||"latest"}`)),w++;const f=u+w;console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${u}/${f}`)} ${w>0?chalk.red(`✗ ${w} missing`):chalk.green("All 110 ready!")}`),w>0&&console.log(chalk.gray(" Install everything: ")+chalk.white("env setup")+chalk.gray(" (~5 min, one-time)")),console.log(chalk.gray(" You are back at the ")+chalk.cyan("icoa>")+chalk.gray(" prompt. ")+chalk.cyan("help")+chalk.gray(" for all commands.")),console.log()}