icoa-cli 1.8.5 → 1.9.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.
@@ -61,9 +61,9 @@ const SYSTEM_TOOLS = [
61
61
  { name: 'as', check: CMD('as'), category: 'Compilers & Build' },
62
62
  { name: 'ld', check: CMD('ld'), category: 'Compilers & Build' },
63
63
  { name: 'pkg-config', check: CMD('pkg-config'), brew: 'pkg-config', apt: 'pkg-config', category: 'Compilers & Build' },
64
- // Python (3)
65
- { name: 'python3', check: W ? 'python --version' : 'python3 --version', brew: 'python@3.12', apt: 'python3', choco: 'python312', category: 'Python Runtime' },
66
- { name: 'pip3', check: W ? 'pip --version' : 'pip3 --version', category: 'Python Runtime' },
64
+ // Python (3) — prefer brew 3.12 on macOS
65
+ { 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' },
66
+ { name: 'pip3', check: process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12 --version' : (W ? 'pip --version' : 'pip3 --version'), category: 'Python Runtime' },
67
67
  { name: 'python3-venv', check: W ? 'python -c "import venv"' : 'python3 -c "import venv"', apt: 'python3-venv', category: 'Python Runtime' },
68
68
  // Networking (12)
69
69
  { name: 'curl', check: CMD('curl'), brew: 'curl', apt: 'curl', choco: 'curl', category: 'Networking' },
@@ -158,30 +158,92 @@ function isInstalled(check) {
158
158
  }
159
159
  }
160
160
  function getVersion(name) {
161
+ // Version commands for each tool
162
+ const versionCmds = {
163
+ 'python3': process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/python3.12 --version' : 'python3 --version',
164
+ 'pip3': process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12 --version' : 'pip3 --version',
165
+ 'gcc': 'gcc --version',
166
+ 'g++': 'g++ --version',
167
+ 'make': 'make --version',
168
+ 'nasm': 'nasm --version',
169
+ 'cmake': 'cmake --version',
170
+ 'vim': 'vim --version',
171
+ 'nano': 'nano --version',
172
+ 'tmux': 'tmux -V',
173
+ 'screen': 'screen --version',
174
+ 'curl': 'curl --version',
175
+ 'wget': 'wget --version',
176
+ 'nmap': 'nmap --version',
177
+ 'ssh': 'ssh -V',
178
+ 'socat': 'socat -V',
179
+ 'gdb': 'gdb --version',
180
+ 'radare2': 'r2 -v',
181
+ 'upx': 'upx --version',
182
+ 'binwalk': 'binwalk --help',
183
+ 'exiftool': 'exiftool -ver',
184
+ 'john': 'john --help',
185
+ 'hashcat': 'hashcat --version',
186
+ 'openssl': 'openssl version',
187
+ 'gpg': 'gpg --version',
188
+ 'jq': 'jq --version',
189
+ 'sqlite3': 'sqlite3 --version',
190
+ 'git': 'git --version',
191
+ 'docker': 'docker --version',
192
+ 'tshark': 'tshark --version',
193
+ 'tcpdump': 'tcpdump --version',
194
+ 'pdftotext': 'pdftotext -v',
195
+ 'pngcheck': 'pngcheck 2>&1',
196
+ };
197
+ const cmd = versionCmds[name];
198
+ if (!cmd)
199
+ return '';
161
200
  try {
162
- if (name === 'python3')
163
- return execSync('python3 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
164
- if (name === 'gcc') {
165
- const m = execSync('gcc --version', { encoding: 'utf-8' }).match(/(\d+\.\d+[\.\d]*)/);
166
- return m?.[1] || '';
167
- }
168
- if (name === 'docker') {
169
- const m = execSync('docker --version', { encoding: 'utf-8' }).match(/(\d+\.\d+\.\d+)/);
170
- return m?.[1] || '';
201
+ const out = execSync(cmd + ' 2>&1', { encoding: 'utf-8', timeout: 3000 }).trim();
202
+ // Extract version number pattern
203
+ const m = out.match(/(\d+\.\d+[\.\d]*)/);
204
+ return m?.[1] || '';
205
+ }
206
+ catch { /* ignore */ }
207
+ return '';
208
+ }
209
+ function getOsInfo() {
210
+ const os = platform();
211
+ try {
212
+ if (os === 'darwin') {
213
+ const ver = execSync('sw_vers -productVersion', { encoding: 'utf-8' }).trim();
214
+ const arch = execSync('uname -m', { encoding: 'utf-8' }).trim();
215
+ return `macOS ${ver} (${arch})`;
171
216
  }
172
- if (name === 'pip3') {
173
- const m = execSync('pip3 --version', { encoding: 'utf-8' }).match(/(\d+\.\d+[\.\d]*)/);
174
- return m?.[1] || '';
217
+ else if (os === 'linux') {
218
+ try {
219
+ const pretty = execSync('cat /etc/os-release | grep PRETTY_NAME', { encoding: 'utf-8' });
220
+ const m = pretty.match(/PRETTY_NAME="(.+)"/);
221
+ const arch = execSync('uname -m', { encoding: 'utf-8' }).trim();
222
+ return m ? `${m[1]} (${arch})` : `Linux (${arch})`;
223
+ }
224
+ catch {
225
+ return 'Linux';
226
+ }
175
227
  }
176
- if (name === 'nmap') {
177
- const m = execSync('nmap --version', { encoding: 'utf-8' }).match(/(\d+\.\d+)/);
178
- return m?.[1] || '';
228
+ else if (os === 'win32') {
229
+ const ver = execSync('ver', { encoding: 'utf-8' }).trim();
230
+ return ver || 'Windows';
179
231
  }
180
232
  }
181
233
  catch { /* ignore */ }
182
- return '';
234
+ return os;
235
+ }
236
+ function getNodeInfo() {
237
+ return `Node.js ${process.version}`;
183
238
  }
184
239
  function getPythonMajorMinor() {
240
+ // On macOS, prefer brew Python 3.12
241
+ if (process.platform === 'darwin') {
242
+ try {
243
+ 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();
244
+ }
245
+ catch { /* fall through */ }
246
+ }
185
247
  try {
186
248
  return execSync('python3 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"', { encoding: 'utf-8' }).trim();
187
249
  }
@@ -189,6 +251,20 @@ function getPythonMajorMinor() {
189
251
  return '';
190
252
  }
191
253
  }
254
+ function getPythonFullVersion() {
255
+ if (process.platform === 'darwin') {
256
+ try {
257
+ return execSync('/opt/homebrew/opt/python@3.12/bin/python3.12 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
258
+ }
259
+ catch { /* fall through */ }
260
+ }
261
+ try {
262
+ return execSync('python3 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
263
+ }
264
+ catch {
265
+ return '';
266
+ }
267
+ }
192
268
  export function registerEnvCommand(program) {
193
269
  const envCmd = program.command('env').description('Manage competition environment');
194
270
  envCmd.command('status').alias('check').description('Check all 109 tools').action(() => showStatus());
@@ -198,24 +274,22 @@ export function registerEnvCommand(program) {
198
274
  function showStatus() {
199
275
  console.log();
200
276
  const os = platform();
201
- const osName = os === 'darwin' ? 'macOS' : os === 'linux' ? 'Linux' : 'Windows';
202
277
  const pm = os === 'darwin' ? 'brew' : os === 'linux' ? 'apt' : 'choco';
203
- console.log(chalk.bold.white(' ICOA Competition Environment (109 commands)'));
204
- console.log(chalk.gray(` Platform: ${osName} | Package Manager: ${pm} | Python: ${PYTHON_TARGET}.x`));
278
+ console.log(chalk.bold.white(' ICOA Competition Environment'));
279
+ console.log(chalk.gray(' ─────────────────────────────────────────────'));
280
+ console.log(chalk.gray(' OS: ') + chalk.white(getOsInfo()));
281
+ console.log(chalk.gray(' Node: ') + chalk.white(getNodeInfo()));
282
+ console.log(chalk.gray(' Package: ') + chalk.white(pm));
283
+ console.log(chalk.gray(' Target: ') + chalk.white(`Python ${PYTHON_TARGET}.x`));
205
284
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
206
- // Python version check
285
+ // Python version check — use brew 3.12 on macOS
207
286
  const pyVer = getPythonMajorMinor();
208
- if (pyVer) {
209
- const fullVer = getVersion('python3');
210
- if (pyVer === '3.12') {
211
- console.log(chalk.green(` ✓ Python ${fullVer}`) + chalk.gray(' (recommended)'));
212
- }
213
- else if (pyVer === '3.11' || pyVer === '3.13') {
214
- console.log(chalk.yellow(` ~ Python ${fullVer}`) + chalk.gray(' (3.12.x recommended for full compatibility)'));
215
- }
216
- else {
217
- console.log(chalk.red(` ✗ Python ${fullVer}`) + chalk.gray(' (3.12.x required — some tools may not work)'));
218
- }
287
+ const fullVer = getPythonFullVersion();
288
+ if (pyVer === '3.12') {
289
+ console.log(chalk.green(` ✓ Python ${fullVer}`) + chalk.gray(' (recommended)'));
290
+ }
291
+ else if (pyVer) {
292
+ console.log(chalk.yellow(` ~ Python ${fullVer}`) + chalk.gray(' (3.12.x recommended)'));
219
293
  }
220
294
  else {
221
295
  console.log(chalk.red(' ✗ Python 3 not found'));
@@ -242,6 +316,7 @@ function showStatus() {
242
316
  }
243
317
  }
244
318
  currentCategory = '';
319
+ const pipExe = os === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12' : 'pip3';
245
320
  for (const lib of PYTHON_LIBS) {
246
321
  if (lib.category !== currentCategory) {
247
322
  currentCategory = lib.category;
@@ -249,7 +324,21 @@ function showStatus() {
249
324
  }
250
325
  const ok = isInstalled(lib.check);
251
326
  if (ok) {
252
- console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(` (${lib.install || 'latest'})`));
327
+ // Get actual installed version — try pip3.12, then pip3
328
+ let ver = '';
329
+ for (const pip of [pipExe, 'pip3']) {
330
+ try {
331
+ const pkgName = lib.name.replace('python-magic', 'python_magic').replace('beautifulsoup4', 'beautifulsoup4');
332
+ const out = execSync(`${pip} show ${pkgName} 2>/dev/null | grep Version`, { encoding: 'utf-8', timeout: 3000 });
333
+ const m = out.match(/Version:\s*(\S+)/);
334
+ if (m) {
335
+ ver = m[1];
336
+ break;
337
+ }
338
+ }
339
+ catch { /* try next */ }
340
+ }
341
+ console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(ver ? ` (${ver})` : ''));
253
342
  installed++;
254
343
  }
255
344
  else {
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.8.5')}
39
+ ${chalk.gray('CLI-Native Competition Terminal v1.9.1')}
40
40
 
41
41
  ${LINE}
42
42
  `;
package/dist/repl.js CHANGED
@@ -8,7 +8,7 @@ import { ensureSandbox, runInSandbox, isDockerAvailable } from './lib/sandbox.js
8
8
  import { logCommand } from './lib/logger.js';
9
9
  import { startLogSync, stopLogSync } from './lib/log-sync.js';
10
10
  const INTERCEPT = '__REPL_NO_EXIT__';
11
- const VERSION = '1.8.5';
11
+ const VERSION = '1.9.1';
12
12
  export async function startRepl(program, resumeMode) {
13
13
  const config = getConfig();
14
14
  const connected = isConnected();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "1.8.5",
3
+ "version": "1.9.1",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {