freebuff 0.0.98 → 0.0.99

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/index.js +175 -24
  2. package/package.json +5 -4
package/index.js CHANGED
@@ -74,6 +74,14 @@ function shouldExitAlternateScreen(code, signal) {
74
74
  return Boolean(signal) || isWindowsNativeCrashCode(code)
75
75
  }
76
76
 
77
+ function isIllegalInstructionExit(code, signal) {
78
+ const unsignedCode = getUnsignedExitCode(code)
79
+ return (
80
+ signal === 'SIGILL' ||
81
+ (process.platform === 'win32' && unsignedCode === 0xC000001D)
82
+ )
83
+ }
84
+
77
85
  function createConfig(packageName) {
78
86
  const homeDir = os.homedir()
79
87
  const configDir = path.join(homeDir, '.config', 'manicode')
@@ -164,10 +172,17 @@ function trackUpdateFailed(errorMessage, version, context = {}) {
164
172
 
165
173
  const PLATFORM_TARGETS = {
166
174
  'linux-x64': `${packageName}-linux-x64.tar.gz`,
175
+ 'linux-x64-baseline': `${packageName}-linux-x64-baseline.tar.gz`,
167
176
  'linux-arm64': `${packageName}-linux-arm64.tar.gz`,
168
177
  'darwin-x64': `${packageName}-darwin-x64.tar.gz`,
169
178
  'darwin-arm64': `${packageName}-darwin-arm64.tar.gz`,
170
179
  'win32-x64': `${packageName}-win32-x64.tar.gz`,
180
+ 'win32-x64-baseline': `${packageName}-win32-x64-baseline.tar.gz`,
181
+ }
182
+
183
+ const BASELINE_FALLBACK_TARGETS = {
184
+ 'linux-x64': 'linux-x64-baseline',
185
+ 'win32-x64': 'win32-x64-baseline',
171
186
  }
172
187
 
173
188
  const term = {
@@ -186,6 +201,84 @@ const term = {
186
201
  },
187
202
  }
188
203
 
204
+ function getPlatformKey() {
205
+ return `${process.platform}-${process.arch}`
206
+ }
207
+
208
+ function getTargetOverride() {
209
+ const envNames = [
210
+ `${packageName.toUpperCase()}_BINARY_TARGET`,
211
+ 'CODEBUFF_BINARY_TARGET',
212
+ 'CLI_BINARY_TARGET',
213
+ ]
214
+
215
+ for (const envName of envNames) {
216
+ const target = process.env[envName]
217
+ if (target && PLATFORM_TARGETS[target]) {
218
+ return target
219
+ }
220
+ }
221
+
222
+ return null
223
+ }
224
+
225
+ function linuxCpuHasAvx2() {
226
+ if (process.platform !== 'linux' || process.arch !== 'x64') {
227
+ return true
228
+ }
229
+
230
+ try {
231
+ return /\bavx2\b/i.test(fs.readFileSync('/proc/cpuinfo', 'utf8'))
232
+ } catch {
233
+ return true
234
+ }
235
+ }
236
+
237
+ function getDefaultTargetKey() {
238
+ const override = getTargetOverride()
239
+ if (override) {
240
+ return override
241
+ }
242
+
243
+ const platformKey = getPlatformKey()
244
+ if (platformKey === 'linux-x64' && !linuxCpuHasAvx2()) {
245
+ return 'linux-x64-baseline'
246
+ }
247
+
248
+ return platformKey
249
+ }
250
+
251
+ function getBaselineFallbackTargetKey() {
252
+ // Windows has no reliable plain-Node CPU feature check here, so we keep
253
+ // the fast x64 binary first and fall back after the native SIGILL code.
254
+ return BASELINE_FALLBACK_TARGETS[getPlatformKey()] || null
255
+ }
256
+
257
+ function isTargetAllowedForThisMachine(target) {
258
+ const override = getTargetOverride()
259
+ if (override) {
260
+ return target === override
261
+ }
262
+ return (
263
+ target === getDefaultTargetKey() ||
264
+ target === getBaselineFallbackTargetKey()
265
+ )
266
+ }
267
+
268
+ function getDownloadTargetKey() {
269
+ const override = getTargetOverride()
270
+ if (override) {
271
+ return override
272
+ }
273
+
274
+ const metadata = getCurrentMetadata()
275
+ if (metadata?.target && isTargetAllowedForThisMachine(metadata.target)) {
276
+ return metadata.target
277
+ }
278
+
279
+ return getDefaultTargetKey()
280
+ }
281
+
189
282
  async function getLatestVersion() {
190
283
  try {
191
284
  const res = await httpGet(
@@ -214,19 +307,34 @@ function streamToString(stream) {
214
307
 
215
308
  function getCurrentVersion() {
216
309
  try {
217
- if (!fs.existsSync(CONFIG.metadataPath)) {
310
+ const metadata = getCurrentMetadata()
311
+ if (!metadata) {
218
312
  return null
219
313
  }
220
- const metadata = JSON.parse(fs.readFileSync(CONFIG.metadataPath, 'utf8'))
221
314
  if (!fs.existsSync(CONFIG.binaryPath)) {
222
315
  return null
223
316
  }
317
+ const metadataTarget = metadata.target || getPlatformKey()
318
+ if (!isTargetAllowedForThisMachine(metadataTarget)) {
319
+ return null
320
+ }
224
321
  return metadata.version || null
225
322
  } catch (error) {
226
323
  return null
227
324
  }
228
325
  }
229
326
 
327
+ function getCurrentMetadata() {
328
+ try {
329
+ if (!fs.existsSync(CONFIG.metadataPath)) {
330
+ return null
331
+ }
332
+ return JSON.parse(fs.readFileSync(CONFIG.metadataPath, 'utf8'))
333
+ } catch {
334
+ return null
335
+ }
336
+ }
337
+
230
338
  function compareVersions(v1, v2) {
231
339
  if (!v1 || !v2) return 0
232
340
 
@@ -303,13 +411,12 @@ function createProgressBar(percentage, width = 30) {
303
411
  return '[' + '█'.repeat(filled) + '░'.repeat(empty) + ']'
304
412
  }
305
413
 
306
- async function downloadBinary(version) {
307
- const platformKey = `${process.platform}-${process.arch}`
308
- const fileName = PLATFORM_TARGETS[platformKey]
414
+ async function downloadBinary(version, targetKey = getDownloadTargetKey()) {
415
+ const fileName = PLATFORM_TARGETS[targetKey]
309
416
 
310
417
  if (!fileName) {
311
418
  const error = new Error(`Unsupported platform: ${process.platform} ${process.arch}`)
312
- trackUpdateFailed(error.message, version, { stage: 'platform_check' })
419
+ trackUpdateFailed(error.message, version, { stage: 'platform_check', target: targetKey })
313
420
  throw error
314
421
  }
315
422
 
@@ -331,7 +438,7 @@ async function downloadBinary(version) {
331
438
  if (res.statusCode !== 200) {
332
439
  fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
333
440
  const error = new Error(`Download failed: HTTP ${res.statusCode}`)
334
- trackUpdateFailed(error.message, version, { stage: 'http_download', statusCode: res.statusCode })
441
+ trackUpdateFailed(error.message, version, { stage: 'http_download', statusCode: res.statusCode, target: targetKey })
335
442
  throw error
336
443
  }
337
444
 
@@ -373,7 +480,7 @@ async function downloadBinary(version) {
373
480
  const error = new Error(
374
481
  `Binary not found after extraction. Expected: ${CONFIG.binaryName}, Available files: ${files.join(', ')}`,
375
482
  )
376
- trackUpdateFailed(error.message, version, { stage: 'extraction' })
483
+ trackUpdateFailed(error.message, version, { stage: 'extraction', target: targetKey })
377
484
  throw error
378
485
  }
379
486
 
@@ -423,7 +530,7 @@ async function downloadBinary(version) {
423
530
 
424
531
  fs.writeFileSync(
425
532
  CONFIG.metadataPath,
426
- JSON.stringify({ version }, null, 2),
533
+ JSON.stringify({ version, target: targetKey }, null, 2),
427
534
  )
428
535
  } finally {
429
536
  if (fs.existsSync(CONFIG.tempDownloadDir)) {
@@ -505,14 +612,7 @@ async function checkForUpdates(runningProcess, exitListener) {
505
612
  await downloadBinary(latestVersion)
506
613
 
507
614
  const newChild = spawnInstalledBinary({ detached: false })
508
-
509
- newChild.on('exit', (code, signal) => {
510
- resetTerminal({
511
- exitAlternateScreen: shouldExitAlternateScreen(code, signal),
512
- })
513
- printCrashDiagnostics(code, signal)
514
- process.exit(signal ? 1 : (code || 0))
515
- })
615
+ attachExitHandler(newChild)
516
616
 
517
617
  return new Promise(() => {})
518
618
  }
@@ -524,9 +624,7 @@ async function checkForUpdates(runningProcess, exitListener) {
524
624
  function printCrashDiagnostics(code, signal) {
525
625
  // Windows NTSTATUS codes (unsigned DWORD)
526
626
  const unsignedCode = getUnsignedExitCode(code)
527
- const isIllegalInstruction =
528
- signal === 'SIGILL' ||
529
- (process.platform === 'win32' && unsignedCode === 0xC000001D)
627
+ const isIllegalInstruction = isIllegalInstructionExit(code, signal)
530
628
  const isAccessViolation =
531
629
  signal === 'SIGSEGV' ||
532
630
  (process.platform === 'win32' && unsignedCode === 0xC0000005)
@@ -635,12 +733,57 @@ function spawnInstalledBinary(options = {}) {
635
733
  return child
636
734
  }
637
735
 
638
- async function main() {
639
- await ensureBinaryExists()
736
+ async function tryFallbackToBaseline(code, signal) {
737
+ if (!isIllegalInstructionExit(code, signal)) {
738
+ return false
739
+ }
640
740
 
641
- const child = spawnInstalledBinary()
741
+ const fallbackTarget = getBaselineFallbackTargetKey()
742
+ if (!fallbackTarget) {
743
+ return false
744
+ }
745
+
746
+ const metadata = getCurrentMetadata()
747
+ const currentTarget = metadata?.target || getDefaultTargetKey()
748
+ if (currentTarget === fallbackTarget) {
749
+ return false
750
+ }
751
+
752
+ const version = metadata?.version || (await getLatestVersion())
753
+ if (!version) {
754
+ return false
755
+ }
756
+
757
+ resetTerminal({
758
+ exitAlternateScreen: shouldExitAlternateScreen(code, signal),
759
+ })
760
+ console.error('')
761
+ console.error(
762
+ `${packageName} is switching to the older-CPU binary for this machine.`,
763
+ )
764
+
765
+ try {
766
+ await downloadBinary(version, fallbackTarget)
767
+ } catch (error) {
768
+ term.clearLine()
769
+ console.error(`Failed to download ${fallbackTarget}: ${error.message}`)
770
+ return false
771
+ }
772
+
773
+ const child = spawnInstalledBinary({ detached: false })
774
+ attachExitHandler(child, false)
775
+ return true
776
+ }
777
+
778
+ function attachExitHandler(child, allowBaselineFallback = true) {
779
+ const exitListener = async (code, signal) => {
780
+ if (
781
+ allowBaselineFallback &&
782
+ (await tryFallbackToBaseline(code, signal))
783
+ ) {
784
+ return
785
+ }
642
786
 
643
- const exitListener = (code, signal) => {
644
787
  resetTerminal({
645
788
  exitAlternateScreen: shouldExitAlternateScreen(code, signal),
646
789
  })
@@ -649,6 +792,14 @@ async function main() {
649
792
  }
650
793
 
651
794
  child.on('exit', exitListener)
795
+ return exitListener
796
+ }
797
+
798
+ async function main() {
799
+ await ensureBinaryExists()
800
+
801
+ const child = spawnInstalledBinary()
802
+ const exitListener = attachExitHandler(child)
652
803
 
653
804
  setTimeout(() => {
654
805
  checkForUpdates(child, exitListener)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freebuff",
3
- "version": "0.0.98",
3
+ "version": "0.0.99",
4
4
  "description": "The world's strongest free coding agent",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -33,10 +33,11 @@
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",
36
- "url": "https://github.com/CodebuffAI/codebuff.git"
36
+ "url": "git+https://github.com/CodebuffAI/freebuff-private.git"
37
37
  },
38
- "homepage": "https://codebuff.com",
38
+ "homepage": "https://freebuff.com",
39
39
  "publishConfig": {
40
- "access": "public"
40
+ "access": "public",
41
+ "provenance": false
41
42
  }
42
43
  }