freebuff 0.0.115 → 0.0.118
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +132 -18
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { spawn } = require('child_process')
|
|
3
|
+
const { spawn, execFileSync } = require('child_process')
|
|
4
4
|
const fs = require('fs')
|
|
5
5
|
const http = require('http')
|
|
6
6
|
const https = require('https')
|
|
@@ -26,6 +26,8 @@ const SAFE_TERMINAL_RESET_SEQUENCES =
|
|
|
26
26
|
'\x1b[?1006l' + // Disable SGR extended mouse mode
|
|
27
27
|
'\x1b[?1004l' + // Disable focus reporting
|
|
28
28
|
'\x1b[?2004l' + // Disable bracketed paste mode
|
|
29
|
+
'\x1b[<u' + // Pop kitty keyboard protocol flags
|
|
30
|
+
'\x1b[>4;0m' + // Reset modifyOtherKeys
|
|
29
31
|
'\x1b[?25h' // Show cursor
|
|
30
32
|
|
|
31
33
|
const FULL_TERMINAL_RESET_SEQUENCES =
|
|
@@ -223,15 +225,99 @@ function getTargetOverride() {
|
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
function linuxCpuHasAvx2() {
|
|
226
|
-
|
|
228
|
+
try {
|
|
229
|
+
return /\bavx2\b/i.test(fs.readFileSync('/proc/cpuinfo', 'utf8'))
|
|
230
|
+
} catch {
|
|
227
231
|
return true
|
|
228
232
|
}
|
|
233
|
+
}
|
|
229
234
|
|
|
235
|
+
// Returns true (AVX2 present), false (absent), or null (couldn't determine).
|
|
236
|
+
// Ask the OS directly via IsProcessorFeaturePresent (kernel32), which is
|
|
237
|
+
// backed by CPUID — far more reliable than matching CPU model names, and it
|
|
238
|
+
// works on the stock Windows PowerShell that ships with every supported
|
|
239
|
+
// Windows version. Feature 40 = PF_AVX2_INSTRUCTIONS_AVAILABLE.
|
|
240
|
+
function probeWindowsAvx2() {
|
|
241
|
+
const script =
|
|
242
|
+
"$f = Add-Type -MemberDefinition '[DllImport(\"kernel32.dll\")] " +
|
|
243
|
+
"public static extern bool IsProcessorFeaturePresent(uint feature);' " +
|
|
244
|
+
"-Name Cpu -Namespace Win32 -PassThru; $f::IsProcessorFeaturePresent(40)"
|
|
230
245
|
try {
|
|
231
|
-
|
|
246
|
+
const out = execFileSync(
|
|
247
|
+
'powershell.exe',
|
|
248
|
+
['-NoProfile', '-NonInteractive', '-Command', script],
|
|
249
|
+
{ encoding: 'utf8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] },
|
|
250
|
+
).trim()
|
|
251
|
+
if (out === 'True') return true
|
|
252
|
+
if (out === 'False') return false
|
|
253
|
+
return null
|
|
232
254
|
} catch {
|
|
255
|
+
// No PowerShell, locked-down policy, timeout, etc. — inconclusive.
|
|
256
|
+
return null
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let _hasAvx2Cache
|
|
261
|
+
|
|
262
|
+
function machineHasAvx2() {
|
|
263
|
+
if (_hasAvx2Cache === undefined) {
|
|
264
|
+
_hasAvx2Cache = detectMachineHasAvx2()
|
|
265
|
+
}
|
|
266
|
+
return _hasAvx2Cache
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function detectMachineHasAvx2() {
|
|
270
|
+
if (process.arch !== 'x64') {
|
|
233
271
|
return true
|
|
234
272
|
}
|
|
273
|
+
|
|
274
|
+
// Linux detection is a cheap file read, so we don't bother persisting it.
|
|
275
|
+
if (process.platform === 'linux') {
|
|
276
|
+
return linuxCpuHasAvx2()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (process.platform !== 'win32') {
|
|
280
|
+
return true
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Windows detection shells out to PowerShell. getDefaultTargetKey runs on
|
|
284
|
+
// every launch (via the version check), so cache the result on disk to keep
|
|
285
|
+
// startup fast after the first probe.
|
|
286
|
+
const cached = readCachedAvx2()
|
|
287
|
+
if (cached !== null) {
|
|
288
|
+
return cached
|
|
289
|
+
}
|
|
290
|
+
const detected = probeWindowsAvx2()
|
|
291
|
+
if (detected === null) {
|
|
292
|
+
// Inconclusive probe: assume AVX2 for this launch and rely on the SIGILL
|
|
293
|
+
// fallback, but don't persist it — a transient failure must not lock in a
|
|
294
|
+
// wrong answer for the lifetime of the install. We'll re-probe next launch.
|
|
295
|
+
return true
|
|
296
|
+
}
|
|
297
|
+
writeCachedAvx2(detected)
|
|
298
|
+
return detected
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function getCpuFeatureCachePath() {
|
|
302
|
+
return path.join(CONFIG.configDir, 'cpu-features.json')
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function readCachedAvx2() {
|
|
306
|
+
try {
|
|
307
|
+
const cache = JSON.parse(fs.readFileSync(getCpuFeatureCachePath(), 'utf8'))
|
|
308
|
+
return typeof cache.avx2 === 'boolean' ? cache.avx2 : null
|
|
309
|
+
} catch {
|
|
310
|
+
return null
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function writeCachedAvx2(value) {
|
|
315
|
+
try {
|
|
316
|
+
fs.mkdirSync(CONFIG.configDir, { recursive: true })
|
|
317
|
+
fs.writeFileSync(getCpuFeatureCachePath(), JSON.stringify({ avx2: value }))
|
|
318
|
+
} catch {
|
|
319
|
+
// Best effort; we'll just re-probe next launch.
|
|
320
|
+
}
|
|
235
321
|
}
|
|
236
322
|
|
|
237
323
|
function getDefaultTargetKey() {
|
|
@@ -241,16 +327,26 @@ function getDefaultTargetKey() {
|
|
|
241
327
|
}
|
|
242
328
|
|
|
243
329
|
const platformKey = getPlatformKey()
|
|
244
|
-
|
|
245
|
-
|
|
330
|
+
// Select the binary up front from explicit CPU feature detection rather than
|
|
331
|
+
// optimistically launching the AVX2 build and waiting for it to crash with
|
|
332
|
+
// an illegal instruction. The crash isn't always a clean immediate failure —
|
|
333
|
+
// it can surface later from a deeper code path — so older CPUs (e.g. an
|
|
334
|
+
// Intel Xeon with AVX but no AVX2) are safer on baseline from the start.
|
|
335
|
+
//
|
|
336
|
+
// This assumes every baseline target is gated on AVX2 specifically, which
|
|
337
|
+
// holds today (only linux-x64 and win32-x64 have baseline builds, both
|
|
338
|
+
// AVX2-gated). If a baseline build is ever added for a different reason, give
|
|
339
|
+
// BASELINE_FALLBACK_TARGETS a per-target capability and check that instead.
|
|
340
|
+
if (BASELINE_FALLBACK_TARGETS[platformKey] && !machineHasAvx2()) {
|
|
341
|
+
return BASELINE_FALLBACK_TARGETS[platformKey]
|
|
246
342
|
}
|
|
247
343
|
|
|
248
344
|
return platformKey
|
|
249
345
|
}
|
|
250
346
|
|
|
251
347
|
function getBaselineFallbackTargetKey() {
|
|
252
|
-
//
|
|
253
|
-
//
|
|
348
|
+
// Runtime safety net: if proactive detection was unavailable or wrong and the
|
|
349
|
+
// optimized binary still dies with SIGILL, fall back to baseline.
|
|
254
350
|
return BASELINE_FALLBACK_TARGETS[getPlatformKey()] || null
|
|
255
351
|
}
|
|
256
352
|
|
|
@@ -259,9 +355,11 @@ function isTargetAllowedForThisMachine(target) {
|
|
|
259
355
|
if (override) {
|
|
260
356
|
return target === override
|
|
261
357
|
}
|
|
358
|
+
// Check the baseline fallback first: it's always safe on its platform and
|
|
359
|
+
// avoids running CPU detection when a baseline binary is already installed.
|
|
262
360
|
return (
|
|
263
|
-
target ===
|
|
264
|
-
target ===
|
|
361
|
+
target === getBaselineFallbackTargetKey() ||
|
|
362
|
+
target === getDefaultTargetKey()
|
|
265
363
|
)
|
|
266
364
|
}
|
|
267
365
|
|
|
@@ -643,8 +741,8 @@ function printCrashDiagnostics(code, signal) {
|
|
|
643
741
|
if (isIllegalInstruction) {
|
|
644
742
|
console.error('Your CPU may not support the required instruction set (AVX2).')
|
|
645
743
|
console.error('This typically affects CPUs from before 2013.')
|
|
646
|
-
console.error('Unfortunately, this binary is not compatible with your system.')
|
|
647
744
|
console.error('')
|
|
745
|
+
printBaselineOverrideHint()
|
|
648
746
|
} else if (isAccessViolation) {
|
|
649
747
|
console.error('The binary crashed with an access violation.')
|
|
650
748
|
console.error('')
|
|
@@ -657,16 +755,33 @@ function printCrashDiagnostics(code, signal) {
|
|
|
657
755
|
console.error('')
|
|
658
756
|
}
|
|
659
757
|
|
|
660
|
-
|
|
661
|
-
console.error(` Platform: ${process.platform} ${process.arch}`)
|
|
662
|
-
console.error(` Node: ${process.version}`)
|
|
663
|
-
console.error(` Binary: ${CONFIG.binaryPath}`)
|
|
758
|
+
printSystemInfo()
|
|
664
759
|
console.error('')
|
|
665
760
|
console.error('Please report this issue at:')
|
|
666
761
|
console.error(' https://github.com/CodebuffAI/codebuff/issues')
|
|
667
762
|
console.error('')
|
|
668
763
|
}
|
|
669
764
|
|
|
765
|
+
function printBaselineOverrideHint() {
|
|
766
|
+
const fallbackTarget = getBaselineFallbackTargetKey()
|
|
767
|
+
if (!fallbackTarget) return
|
|
768
|
+
console.error('To force the baseline (non-AVX2) build, set:')
|
|
769
|
+
console.error(` ${packageName.toUpperCase()}_BINARY_TARGET=${fallbackTarget}`)
|
|
770
|
+
console.error('')
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function printSystemInfo() {
|
|
774
|
+
const metadata = getCurrentMetadata()
|
|
775
|
+
console.error('System info:')
|
|
776
|
+
console.error(` Platform: ${process.platform} ${process.arch}`)
|
|
777
|
+
console.error(` Node: ${process.version}`)
|
|
778
|
+
if (process.arch === 'x64') {
|
|
779
|
+
console.error(` AVX2: ${machineHasAvx2() ? 'yes' : 'no'}`)
|
|
780
|
+
}
|
|
781
|
+
console.error(` Target: ${metadata?.target || getDefaultTargetKey()}`)
|
|
782
|
+
console.error(` Binary: ${CONFIG.binaryPath}`)
|
|
783
|
+
}
|
|
784
|
+
|
|
670
785
|
function getInstalledBinaryStatus() {
|
|
671
786
|
try {
|
|
672
787
|
const stats = fs.statSync(CONFIG.binaryPath)
|
|
@@ -682,10 +797,7 @@ function printSpawnFailure(err) {
|
|
|
682
797
|
|
|
683
798
|
console.error(`Failed to start ${packageName}: ${err.message}${code}`)
|
|
684
799
|
console.error('')
|
|
685
|
-
|
|
686
|
-
console.error(` Platform: ${process.platform} ${process.arch}`)
|
|
687
|
-
console.error(` Node: ${process.version}`)
|
|
688
|
-
console.error(` Binary: ${CONFIG.binaryPath}`)
|
|
800
|
+
printSystemInfo()
|
|
689
801
|
console.error(` Exists: ${getInstalledBinaryStatus()}`)
|
|
690
802
|
|
|
691
803
|
if (process.platform === 'win32') {
|
|
@@ -697,6 +809,8 @@ function printSpawnFailure(err) {
|
|
|
697
809
|
'or quarantines the downloaded executable, or when the binary requires',
|
|
698
810
|
)
|
|
699
811
|
console.error('CPU instructions that are not available on this machine.')
|
|
812
|
+
console.error('')
|
|
813
|
+
printBaselineOverrideHint()
|
|
700
814
|
}
|
|
701
815
|
|
|
702
816
|
console.error('')
|