Lines 1-108javascript
2const { spawnSync } = require('child_process')
3const { join } = require('path')
4const { existsSync, mkdirSync, createWriteStream } = require('fs')
5const https = require('https')
6const os = require('os')
8const REPO = 'Apex-Accelerator/apexcli'
9const VERSION = require('./package.json').releaseVersion || require('./package.json').version
10const isWin = process.platform === 'win32'
11const BIN_DIR = join(os.homedir(), '.apex', 'bin')
12const BIN_PATH = join(BIN_DIR, isWin ? 'apex.exe' : 'apex')
14function getPlatformTarget() {
15 const p = process.platform, a = process.arch
16 if (p === 'darwin' && a === 'arm64') return 'darwin-arm64'
17 if (p === 'darwin' && a === 'x64') return 'darwin-x64'
18 if (p === 'win32' && a === 'x64') return 'windows-x64'
19 throw new Error(`Unsupported platform: ${p}-${a}. Currently supported: macOS (arm64, x64), Windows (x64).`)
25 const cleanup = (err) => {
27 try { require('fs').unlinkSync(dest) } catch {}
31 https.get(u, { headers: { 'User-Agent': 'apex-installer' } }, (res) => {
32 if (res.statusCode === 301 || res.statusCode === 302) { req(res.headers.location); return }
33 if (res.statusCode !== 200) { cleanup(new Error(`HTTP ${res.statusCode}`)); return }
35 file.on('finish', () => { file.close(); resolve() })
36 }).on('error', cleanup)
42async function ensureBinary() {
43 if (existsSync(BIN_PATH)) return
45 console.log('Downloading Apex Copilot (~114MB), please wait...')
46 const target = getPlatformTarget()
47 const assetName = isWin ? `apex-${target}.exe` : `apex-${target}`
48 const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${assetName}`
50 mkdirSync(BIN_DIR, { recursive: true })
51 await download(url, BIN_PATH)
53 const { chmodSync } = require('fs')
54 if (!isWin) chmodSync(BIN_PATH, 0o755)
MediumAi Review Evidence
The user-invoked CLI downloads an executable from GitHub Releases into the home directory without an integrity check.
apex.cjsView on unpkg · L45 56 // Windows: download native addon
58 const nativesDir = join(os.homedir(), '.apex', 'natives', '16.3.6')
59 const nodeFile = 'pi_natives.win32-x64-baseline.node'
60 const nodePath = join(nativesDir, nodeFile)
61 if (!existsSync(nodePath)) {
62 console.log('Downloading native addon...')
63 mkdirSync(nativesDir, { recursive: true })
64 await download(`https://github.com/${REPO}/releases/download/v${VERSION}/${nodeFile}`, nodePath)
70 const verifyPath = join(os.homedir(), '.apex', 'apex-verify.exe')
71 const verifyVersionPath = join(os.homedir(), '.apex', '.verify-version-win')
72 let needsUpdate = !existsSync(verifyPath)
75 const saved = require('fs').readFileSync(verifyVersionPath, 'utf8').trim()
76 if (saved !== VERSION) needsUpdate = true
77 } catch { needsUpdate = true }
80 mkdirSync(join(os.homedir(), '.apex'), { recursive: true })
81 await download(`https://github.com/${REPO}/releases/download/v${VERSION}/apex-verify-windows.exe`, verifyPath)
82 require('fs').writeFileSync(verifyVersionPath, VERSION)
86 // Mac: download apex-verify
87 if (process.platform === 'darwin') {
88 const verifyPath = join(os.homedir(), '.apex', 'apex-verify')
89 if (!existsSync(verifyPath)) {
90 mkdirSync(join(os.homedir(), '.apex'), { recursive: true })
91 await download(`https://github.com/${REPO}/releases/download/v${VERSION}/apex-verify-darwin`, verifyPath)
92 require('fs').chmodSync(verifyPath, 0o755)
99ensureBinary().then(() => {
100 const result = spawnSync(BIN_PATH, process.argv.slice(2), {
HighRemote System File Write
Source writes bytes from a remote response into a privileged operating-system path.
apex.cjsView on unpkg · L1 101 stdio: 'inherit', env: process.env
102 })
HighSame File Env Network Execution
A single source file combines environment access, network access, and code or shell execution; review context before blocking.
apex.cjsView on unpkg · L90 103 process.exit(result.status ?? 0)
MediumAi Review Evidence
It marks that downloaded file executable and runs it while passing through the caller's environment.
apex.cjsView on unpkg · L99 105 console.error('Failed to download Apex:', err.message)