freebuff 0.0.135 → 0.0.136

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 (2) hide show
  1. package/launcher.js +61 -56
  2. package/package.json +1 -1
package/launcher.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { spawn, execFileSync } = require('child_process')
3
+ const { spawn } = require('child_process')
4
4
  const fs = require('fs')
5
5
  const http = require('http')
6
6
  const https = require('https')
@@ -21,6 +21,9 @@ function createLauncher(productConfig) {
21
21
  telemetryEvent = 'cli.update_codebuff_failed',
22
22
  telemetryProperties = {},
23
23
  tempDownloadDirName = `.${packageName}-download-temp`,
24
+ // Tests only. os.homedir() ignores $HOME under `bun test`, so pointing HOME
25
+ // at a temp dir is not enough to keep a test off the real ~/.config.
26
+ configDir: configDirOverride = null,
24
27
  } = productConfig
25
28
 
26
29
  /**
@@ -96,7 +99,8 @@ function createLauncher(productConfig) {
96
99
 
97
100
  function createConfig(packageName) {
98
101
  const homeDir = os.homedir()
99
- const configDir = path.join(homeDir, '.config', 'manicode')
102
+ const configDir =
103
+ configDirOverride || path.join(homeDir, '.config', 'manicode')
100
104
  const binaryName =
101
105
  process.platform === 'win32' ? `${packageName}.exe` : packageName
102
106
 
@@ -245,35 +249,6 @@ function createLauncher(productConfig) {
245
249
  }
246
250
  }
247
251
 
248
- // Returns true (AVX2 present), false (absent), or null (couldn't determine).
249
- // Ask the OS directly via IsProcessorFeaturePresent (kernel32), which is
250
- // backed by CPUID — far more reliable than matching CPU model names, and it
251
- // works on the stock Windows PowerShell that ships with every supported
252
- // Windows version. Feature 40 = PF_AVX2_INSTRUCTIONS_AVAILABLE.
253
- function probeWindowsAvx2() {
254
- const script =
255
- '$f = Add-Type -MemberDefinition \'[DllImport("kernel32.dll")] ' +
256
- "public static extern bool IsProcessorFeaturePresent(uint feature);' " +
257
- '-Name Cpu -Namespace Win32 -PassThru; $f::IsProcessorFeaturePresent(40)'
258
- try {
259
- const out = execFileSync(
260
- 'powershell.exe',
261
- ['-NoProfile', '-NonInteractive', '-Command', script],
262
- {
263
- encoding: 'utf8',
264
- timeout: 5000,
265
- stdio: ['ignore', 'pipe', 'ignore'],
266
- },
267
- ).trim()
268
- if (out === 'True') return true
269
- if (out === 'False') return false
270
- return null
271
- } catch {
272
- // No PowerShell, locked-down policy, timeout, etc. — inconclusive.
273
- return null
274
- }
275
- }
276
-
277
252
  let _hasAvx2Cache
278
253
 
279
254
  function machineHasAvx2() {
@@ -288,31 +263,41 @@ function createLauncher(productConfig) {
288
263
  return true
289
264
  }
290
265
 
291
- // Linux detection is a cheap file read, so we don't bother persisting it.
266
+ // A recorded illegal-instruction crash outranks everything below it: the
267
+ // binary actually failed on this machine, which beats any inference we
268
+ // could make about the CPU.
269
+ const recorded = readCachedAvx2()
270
+ if (recorded !== null) {
271
+ return recorded
272
+ }
273
+
274
+ // Linux can just ask, and a file read is cheap enough not to cache.
292
275
  if (process.platform === 'linux') {
293
276
  return linuxCpuHasAvx2()
294
277
  }
295
278
 
296
- if (process.platform !== 'win32') {
297
- return true
298
- }
279
+ // Everything else assumes AVX2 — true of every x64 CPU since ~2013.
280
+ //
281
+ // Windows is the case that matters, since it's the only other platform with
282
+ // a baseline build. It has no /proc/cpuinfo equivalent we can read without
283
+ // spawning something, and the probe that used to fill the gap asked
284
+ // PowerShell to compile a C# stub and P/Invoke
285
+ // kernel32!IsProcessorFeaturePresent — accurate, but a textbook malware
286
+ // shape that Windows Defender flagged as a "Suspicious PowerShell command
287
+ // line" on real user machines. The illegal-instruction handler corrects us
288
+ // instead: tryFallbackToBaseline() calls recordMachineLacksAvx2(), so a
289
+ // machine without AVX2 pays exactly one failed launch and is answered by
290
+ // the cache read above from then on.
291
+ return true
292
+ }
299
293
 
300
- // Windows detection shells out to PowerShell. getDefaultTargetKey runs on
301
- // every launch (via the version check), so cache the result on disk to keep
302
- // startup fast after the first probe.
303
- const cached = readCachedAvx2()
304
- if (cached !== null) {
305
- return cached
306
- }
307
- const detected = probeWindowsAvx2()
308
- if (detected === null) {
309
- // Inconclusive probe: assume AVX2 for this launch and rely on the SIGILL
310
- // fallback, but don't persist it — a transient failure must not lock in a
311
- // wrong answer for the lifetime of the install. We'll re-probe next launch.
312
- return true
313
- }
314
- writeCachedAvx2(detected)
315
- return detected
294
+ // Called from the illegal-instruction fallback. Persisting here is what keeps
295
+ // the optimistic assumption above from costing more than a single crash and
296
+ // it is deliberately separate from the metadata target, so a lost or rewritten
297
+ // metadata file can't resurrect the AVX2 build on a CPU that can't run it.
298
+ function recordMachineLacksAvx2() {
299
+ _hasAvx2Cache = false
300
+ writeCachedAvx2(false)
316
301
  }
317
302
 
318
303
  function getCpuFeatureCachePath() {
@@ -349,11 +334,12 @@ function createLauncher(productConfig) {
349
334
  }
350
335
 
351
336
  const platformKey = getPlatformKey()
352
- // Select the binary up front from explicit CPU feature detection rather than
353
- // optimistically launching the AVX2 build and waiting for it to crash with
354
- // an illegal instruction. The crash isn't always a clean immediate failure —
355
- // it can surface later from a deeper code path — so older CPUs (e.g. an
356
- // Intel Xeon with AVX but no AVX2) are safer on baseline from the start.
337
+ // Linux still detects up front (reading /proc/cpuinfo is free). Windows
338
+ // cannot without spawning a process, and the PowerShell probe that used to
339
+ // do it tripped Defender, so Windows is optimistic-then-corrected: see
340
+ // detectMachineHasAvx2() and tryFallbackToBaseline(). Once a machine has
341
+ // failed once, readCachedAvx2() answers here and baseline is chosen up front
342
+ // exactly as it used to be.
357
343
  //
358
344
  // This assumes every baseline target is gated on AVX2 specifically, which
359
345
  // holds today (only linux-x64 and win32-x64 have baseline builds, both
@@ -1145,6 +1131,11 @@ function createLauncher(productConfig) {
1145
1131
  return false
1146
1132
  }
1147
1133
 
1134
+ // The optimized build just died on an illegal instruction, so this machine
1135
+ // cannot run it. Persist that before downloading, so even if the download
1136
+ // or the relaunch fails we never optimistically pick the AVX2 build again.
1137
+ recordMachineLacksAvx2()
1138
+
1148
1139
  const version = metadata?.version || (await getLatestVersion())
1149
1140
  if (!version) {
1150
1141
  return false
@@ -1211,6 +1202,20 @@ function createLauncher(productConfig) {
1211
1202
  config: productConfig,
1212
1203
  main,
1213
1204
  stopRunningProcess,
1205
+ // Internals exposed for tests only. The AVX2 path is optimistic-then-
1206
+ // corrected (see detectMachineHasAvx2), so the correction has to be
1207
+ // exercised directly — there is no way to make a CI runner lack AVX2.
1208
+ __testing: {
1209
+ detectMachineHasAvx2,
1210
+ recordMachineLacksAvx2,
1211
+ readCachedAvx2,
1212
+ isIllegalInstructionExit,
1213
+ getDefaultTargetKey,
1214
+ getCpuFeatureCachePath,
1215
+ getCurrentVersion,
1216
+ isTargetAllowedForThisMachine,
1217
+ CONFIG,
1218
+ },
1214
1219
  }
1215
1220
  }
1216
1221
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freebuff",
3
- "version": "0.0.135",
3
+ "version": "0.0.136",
4
4
  "description": "The world's strongest free coding agent",
5
5
  "license": "MIT",
6
6
  "bin": {