freebuff 0.1.1 → 0.1.4

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 +284 -45
  2. package/package.json +9 -9
package/launcher.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { spawn } = require('child_process')
3
+ const { execFileSync, spawn } = require('child_process')
4
4
  const crypto = require('crypto')
5
5
  const fs = require('fs')
6
6
  const http = require('http')
@@ -146,6 +146,9 @@ function createLauncher(productConfig) {
146
146
  // Tests only. os.homedir() ignores $HOME under `bun test`, so pointing HOME
147
147
  // at a temp dir is not enough to keep a test off the real ~/.config.
148
148
  configDir: configDirOverride = null,
149
+ // Tests only: stands in for the OS AVX2 probe (/proc/cpuinfo, sysctl),
150
+ // returning true, false, or null for "could not tell".
151
+ cpuAvx2Probe: cpuAvx2ProbeOverride = null,
149
152
  } = productConfig
150
153
 
151
154
  /**
@@ -257,6 +260,52 @@ function createLauncher(productConfig) {
257
260
  )
258
261
  }
259
262
 
263
+ /**
264
+ * Bun's own crash report saying this CPU cannot run the optimized build.
265
+ *
266
+ * On Windows the exit code does not carry that. Bun's crash handler catches
267
+ * EXCEPTION_ILLEGAL_INSTRUCTION itself, prints a report, then leaves through
268
+ * Zig's std.posix.abort(), which on Windows is ExitProcess(3). So an AVX2
269
+ * build on a CPU without AVX2 exits with plain code 3, neither
270
+ * 0xC000001D nor 0xC0000409, and both checks above miss it. The Sept 27
271
+ * report (i3-2100, Bun 1.3.14) is exactly this:
272
+ *
273
+ * CPU: sse42 avx
274
+ * Features: no_avx2
275
+ * panic: Illegal instruction at address 0x7FF61902F82C
276
+ * panicked during a panic. Aborting.
277
+ *
278
+ * The report is in the stderr tail watchLaunch() keeps on Windows. Either line
279
+ * is proof, not a guess. `Features: no_avx2` is Bun's own CPUID answer, and a
280
+ * Bun "Illegal instruction" panic is the same Windows exception
281
+ * 0xC000001D reports, intercepted before it became the exit code. Only Bun's
282
+ * exact formats count, so ordinary output that mentions them does not.
283
+ */
284
+ const BUN_NO_AVX2_FEATURE = /^Features:[^\n]*\bno_avx2\b/m
285
+ const BUN_ILLEGAL_INSTRUCTION_PANIC =
286
+ /^panic(?:\([^)\n]*\))?: Illegal instruction at address 0x[0-9a-f]+/im
287
+
288
+ /**
289
+ * Bun's `CPU:` header line lists the features it detected (`CPU: sse42
290
+ * popcnt avx avx2`). avx2 in that list is Bun's own CPUID saying the CPU has
291
+ * it, so an illegal instruction on such a machine is not a missing AVX2.
292
+ */
293
+ const BUN_CPU_LINE = /^CPU:([^\n]*)$/m
294
+
295
+ function stderrReportsAvx2Present(stderrTail) {
296
+ if (!stderrTail) return false
297
+ const match = BUN_CPU_LINE.exec(sanitizeForReplay(stderrTail))
298
+ return Boolean(match && /(?:^|\s)avx2(?:\s|$)/i.test(match[1]))
299
+ }
300
+
301
+ function stderrReportsMissingCpuFeature(code, signal, stderrTail) {
302
+ if (!stderrTail || (code === 0 && !signal)) return false
303
+ const text = sanitizeForReplay(stderrTail)
304
+ return (
305
+ BUN_NO_AVX2_FEATURE.test(text) || BUN_ILLEGAL_INSTRUCTION_PANIC.test(text)
306
+ )
307
+ }
308
+
260
309
  function createConfig(packageName) {
261
310
  const homeDir = os.homedir()
262
311
  const configDir =
@@ -409,12 +458,75 @@ function createLauncher(productConfig) {
409
458
  return null
410
459
  }
411
460
 
412
- function linuxCpuHasAvx2() {
413
- try {
414
- return /\bavx2\b/i.test(fs.readFileSync('/proc/cpuinfo', 'utf8'))
415
- } catch {
416
- return true
461
+ /**
462
+ * `/proc/cpuinfo` answers for the kernel's view of the CPU: true or false
463
+ * from its `flags` lines, null when it has none to read.
464
+ */
465
+ function parseCpuinfoAvx2(text) {
466
+ if (typeof text !== 'string' || !/^flags\s*:/m.test(text)) return null
467
+ return /^flags\s*:.*\bavx2\b/m.test(text)
468
+ }
469
+
470
+ /** `sysctl -n hw.optional.avx2_0` prints 1 or 0 on an Intel Mac. */
471
+ function parseSysctlAvx2(output) {
472
+ const value = typeof output === 'string' ? output.trim() : ''
473
+ if (value === '1') return true
474
+ if (value === '0') return false
475
+ return null
476
+ }
477
+
478
+ // Where probeCpuAvx2() gets its answer, recorded as the evidence for a pin.
479
+ function cpuProbeSource() {
480
+ if (process.platform === 'linux') return 'cpuinfo'
481
+ if (process.platform === 'darwin') return 'sysctl'
482
+ return 'probe'
483
+ }
484
+
485
+ let _cpuProbeCache
486
+
487
+ /**
488
+ * Ask the OS whether this CPU has AVX2: true, false, or null for "could not
489
+ * tell". Linux reads /proc/cpuinfo. macOS asks sysctl, which costs a
490
+ * subprocess, so this runs only on the crash path, when re-checking an old
491
+ * pin, and when picking a download target for a baseline install, never on
492
+ * an ordinary launch. Windows has no probe: the one we had tripped Defender
493
+ * (see detectMachineHasAvx2), so there Bun's crash report is the evidence.
494
+ */
495
+ function probeCpuAvx2() {
496
+ if (_cpuProbeCache === undefined) {
497
+ _cpuProbeCache = cpuAvx2ProbeOverride
498
+ ? cpuAvx2ProbeOverride()
499
+ : probeCpuAvx2FromOs()
500
+ }
501
+ return _cpuProbeCache
502
+ }
503
+
504
+ function probeCpuAvx2FromOs() {
505
+ if (process.arch !== 'x64') return null
506
+ if (process.platform === 'linux') {
507
+ try {
508
+ return parseCpuinfoAvx2(fs.readFileSync('/proc/cpuinfo', 'utf8'))
509
+ } catch {
510
+ return null
511
+ }
512
+ }
513
+ if (process.platform === 'darwin') {
514
+ // x64 node on Apple Silicon runs under Rosetta, and sysctl (arm64 only)
515
+ // then describes the host, not what Rosetta emulates. No answer there.
516
+ if (/\bApple\b/.test(os.cpus()[0]?.model || '')) return null
517
+ try {
518
+ return parseSysctlAvx2(
519
+ execFileSync('/usr/sbin/sysctl', ['-n', 'hw.optional.avx2_0'], {
520
+ encoding: 'utf8',
521
+ stdio: ['ignore', 'pipe', 'ignore'],
522
+ timeout: 2000,
523
+ }),
524
+ )
525
+ } catch {
526
+ return null
527
+ }
417
528
  }
529
+ return null
418
530
  }
419
531
 
420
532
  let _hasAvx2Cache
@@ -431,17 +543,33 @@ function createLauncher(productConfig) {
431
543
  return true
432
544
  }
433
545
 
434
- // A recorded illegal-instruction crash outranks everything below it: the
435
- // binary actually failed on this machine, which beats any inference we
436
- // could make about the CPU.
437
- const recorded = readCachedAvx2()
438
- if (recorded !== null) {
439
- return recorded
546
+ // A recorded verdict outranks everything below it. Every record now names
547
+ // its evidence: Bun's crash report, the OS probe, or 'crash' for an
548
+ // illegal instruction nothing could explain.
549
+ //
550
+ // A record WITHOUT evidence was written by an older launcher, which pinned
551
+ // baseline on any SIGILL, including a bug on a CPU that has AVX2. Re-check
552
+ // those against the OS once: a CPU with AVX2 gets its record dropped and
553
+ // the optimized build back on the next update (see getDownloadTargetKey).
554
+ const record = readCpuFeatureRecord()
555
+ if (record && (record.avx2 || record.evidence)) {
556
+ return record.avx2
557
+ }
558
+ if (record) {
559
+ const probed = probeCpuAvx2()
560
+ if (probed !== true) {
561
+ writeCpuFeatureRecord(
562
+ false,
563
+ probed === false ? cpuProbeSource() : 'crash',
564
+ )
565
+ return false
566
+ }
567
+ clearCpuFeatureRecord()
440
568
  }
441
569
 
442
570
  // Linux can just ask, and a file read is cheap enough not to cache.
443
571
  if (process.platform === 'linux') {
444
- return linuxCpuHasAvx2()
572
+ return probeCpuAvx2() ?? true
445
573
  }
446
574
 
447
575
  // Everything else assumes AVX2 — true of every x64 CPU since ~2013.
@@ -459,42 +587,77 @@ function createLauncher(productConfig) {
459
587
  return true
460
588
  }
461
589
 
462
- // Called from the illegal-instruction fallback. Persisting here is what keeps
463
- // the optimistic assumption above from costing more than a single crash — and
464
- // it is deliberately separate from the metadata target, so a lost or rewritten
465
- // metadata file can't resurrect the AVX2 build on a CPU that can't run it.
466
- function recordMachineLacksAvx2() {
590
+ /**
591
+ * Positive evidence that this CPU runs the optimized build: a recorded
592
+ * verdict with evidence, or the OS probe. The optimistic default does not
593
+ * count. This is what lets a baseline install move back to the optimized
594
+ * build; without evidence, baseline stays put.
595
+ */
596
+ function knownToHaveAvx2() {
597
+ if (!machineHasAvx2()) return false
598
+ const record = readCpuFeatureRecord()
599
+ if (record?.avx2 === true && record.evidence) return true
600
+ return probeCpuAvx2() === true
601
+ }
602
+
603
+ // Called from the illegal-instruction fallback, only when the CPU is shown
604
+ // to lack AVX2 or nothing can say either way (see tryFallbackToBaseline).
605
+ // Persisting here is what keeps the optimistic assumption above from costing
606
+ // more than a single crash — and it is deliberately separate from the
607
+ // metadata target, so a lost or rewritten metadata file can't resurrect the
608
+ // AVX2 build on a CPU that can't run it.
609
+ function recordMachineLacksAvx2(evidence = 'crash') {
467
610
  _hasAvx2Cache = false
468
- writeCachedAvx2(false)
611
+ writeCpuFeatureRecord(false, evidence)
469
612
  }
470
613
 
471
614
  function getCpuFeatureCachePath() {
472
615
  return path.join(CONFIG.configDir, 'cpu-features.json')
473
616
  }
474
617
 
475
- function readCachedAvx2() {
618
+ /** `{ avx2, evidence }`; evidence is null on a record from an older launcher. */
619
+ function readCpuFeatureRecord() {
476
620
  try {
477
621
  const cache = JSON.parse(
478
622
  fs.readFileSync(getCpuFeatureCachePath(), 'utf8'),
479
623
  )
480
- return typeof cache.avx2 === 'boolean' ? cache.avx2 : null
624
+ if (typeof cache.avx2 !== 'boolean') return null
625
+ return {
626
+ avx2: cache.avx2,
627
+ evidence:
628
+ typeof cache.evidence === 'string' && cache.evidence
629
+ ? cache.evidence
630
+ : null,
631
+ }
481
632
  } catch {
482
633
  return null
483
634
  }
484
635
  }
485
636
 
486
- function writeCachedAvx2(value) {
637
+ function readCachedAvx2() {
638
+ return readCpuFeatureRecord()?.avx2 ?? null
639
+ }
640
+
641
+ function writeCpuFeatureRecord(value, evidence) {
487
642
  try {
488
643
  fs.mkdirSync(CONFIG.configDir, { recursive: true })
489
644
  fs.writeFileSync(
490
645
  getCpuFeatureCachePath(),
491
- JSON.stringify({ avx2: value }),
646
+ JSON.stringify({ avx2: value, evidence }),
492
647
  )
493
648
  } catch {
494
649
  // Best effort; we'll just re-probe next launch.
495
650
  }
496
651
  }
497
652
 
653
+ function clearCpuFeatureRecord() {
654
+ try {
655
+ fs.unlinkSync(getCpuFeatureCachePath())
656
+ } catch {
657
+ // Already gone, or unwritable; either way nothing pins baseline now.
658
+ }
659
+ }
660
+
498
661
  function getDefaultTargetKey() {
499
662
  const override = getTargetOverride()
500
663
  if (override) {
@@ -547,6 +710,17 @@ function createLauncher(productConfig) {
547
710
 
548
711
  const metadata = getCurrentMetadata()
549
712
  if (metadata?.target && isTargetAllowedForThisMachine(metadata.target)) {
713
+ // An installed baseline keeps running (isTargetAllowedForThisMachine
714
+ // always allows it), but it is not a life sentence: once there is
715
+ // evidence the CPU has AVX2, the next download goes back to the optimized
716
+ // build. That is how a machine sent to baseline by a crash that was not a
717
+ // missing AVX2 re-probes on the next version.
718
+ if (
719
+ metadata.target === getBaselineFallbackTargetKey() &&
720
+ knownToHaveAvx2()
721
+ ) {
722
+ return getDefaultTargetKey()
723
+ }
550
724
  return metadata.target
551
725
  }
552
726
 
@@ -1406,7 +1580,9 @@ function createLauncher(productConfig) {
1406
1580
  const { msAlive = null, stderrTail = '' } = context
1407
1581
  // Windows NTSTATUS codes (unsigned DWORD)
1408
1582
  const unsignedCode = getUnsignedExitCode(code)
1409
- const isIllegalInstruction = isIllegalInstructionExit(code, signal)
1583
+ const isIllegalInstruction =
1584
+ isIllegalInstructionExit(code, signal) ||
1585
+ stderrReportsMissingCpuFeature(code, signal, stderrTail)
1410
1586
  const isAccessViolation =
1411
1587
  signal === 'SIGSEGV' ||
1412
1588
  (process.platform === 'win32' && unsignedCode === 0xc0000005)
@@ -1429,7 +1605,15 @@ function createLauncher(productConfig) {
1429
1605
  )
1430
1606
  console.error('This typically affects CPUs from before 2013.')
1431
1607
  console.error('')
1432
- printBaselineOverrideHint()
1608
+ if (getCurrentMetadata()?.target === getBaselineFallbackTargetKey()) {
1609
+ console.error(
1610
+ 'This is already the older-CPU (baseline) build — please include the',
1611
+ )
1612
+ console.error('output below in your report.')
1613
+ console.error('')
1614
+ } else {
1615
+ printBaselineOverrideHint()
1616
+ }
1433
1617
  } else if (isAccessViolation) {
1434
1618
  console.error('The binary crashed with an access violation.')
1435
1619
  console.error('')
@@ -1664,11 +1848,15 @@ function createLauncher(productConfig) {
1664
1848
  }
1665
1849
  }
1666
1850
 
1667
- async function tryFallbackToBaseline(code, signal, msAlive) {
1668
- // Two spellings of one failure, at two levels of certainty. SIGILL /
1669
- // STATUS_ILLEGAL_INSTRUCTION is proof this CPU cannot run this build; a
1670
- // Windows startup abort is a strong suspicion (see isStartupCpuFeatureCrash).
1671
- const confirmed = isIllegalInstructionExit(code, signal)
1851
+ async function tryFallbackToBaseline(code, signal, msAlive, stderrTail = '') {
1852
+ // Three spellings of one failure, at two levels of certainty. SIGILL /
1853
+ // STATUS_ILLEGAL_INSTRUCTION, or Bun's crash report naming the missing
1854
+ // feature (see stderrReportsMissingCpuFeature), is proof this CPU cannot
1855
+ // run this build; a Windows startup abort is a strong suspicion (see
1856
+ // isStartupCpuFeatureCrash).
1857
+ let confirmed =
1858
+ isIllegalInstructionExit(code, signal) ||
1859
+ stderrReportsMissingCpuFeature(code, signal, stderrTail)
1672
1860
  if (!confirmed && !isStartupCpuFeatureCrash(code, signal, msAlive)) {
1673
1861
  return false
1674
1862
  }
@@ -1689,16 +1877,35 @@ function createLauncher(productConfig) {
1689
1877
  return false
1690
1878
  }
1691
1879
 
1692
- // Only a confirmed illegal instruction gets written down. Persisting it
1693
- // before the download is what caps the cost at one crash: even if the
1694
- // download or the relaunch fails, we never optimistically pick the AVX2
1695
- // build again. A suspected crash records nothing — installing the baseline
1696
- // already keeps this machine on it, so a guess that turns out to be wrong
1697
- // costs the slower build instead of leaving cpu-features.json asserting a
1698
- // CPU limitation we never observed.
1699
- if (confirmed) {
1700
- recordMachineLacksAvx2()
1701
- }
1880
+ // An illegal instruction proves the binary used an instruction this
1881
+ // machine refused, not that the instruction was AVX2: a Bun or JIT bug
1882
+ // raises SIGILL too. So ask for evidence before pinning baseline, which
1883
+ // otherwise sticks for good.
1884
+ //
1885
+ // - The CPU lacks AVX2 (Bun's `Features: no_avx2`, or the OS probe):
1886
+ // record it. Persisting before the download is what caps the cost at
1887
+ // one crash: even if the download or the relaunch fails, we never
1888
+ // optimistically pick the AVX2 build again.
1889
+ // - The CPU has AVX2 (the OS probe, or avx2 in Bun's `CPU:` line): this
1890
+ // crash is something else. Run baseline for now, since it may still
1891
+ // start, and record the evidence so the next update goes back to the
1892
+ // optimized build (getDownloadTargetKey). At worst one crash per release.
1893
+ // - No evidence either way (Windows without Bun's report, an unreadable
1894
+ // /proc/cpuinfo, Rosetta): a confirmed crash is pinned as before.
1895
+ // A suspected crash records nothing: installing the baseline already keeps
1896
+ // this machine on it, and cpu-features.json should not assert a CPU
1897
+ // limitation we never observed.
1898
+ const verdict = crashAvx2Verdict(code, signal, stderrTail)
1899
+ if (verdict.avx2 === true) {
1900
+ writeCpuFeatureRecord(true, verdict.evidence)
1901
+ confirmed = false
1902
+ } else if (verdict.avx2 === false) {
1903
+ recordMachineLacksAvx2(verdict.evidence)
1904
+ confirmed = true
1905
+ } else if (confirmed) {
1906
+ recordMachineLacksAvx2('crash')
1907
+ }
1908
+ const cpuHasAvx2 = verdict.avx2 === true
1702
1909
 
1703
1910
  let version = metadata?.version || null
1704
1911
  let binaryChecksums = null
@@ -1716,9 +1923,11 @@ function createLauncher(productConfig) {
1716
1923
  })
1717
1924
  console.error('')
1718
1925
  console.error(
1719
- confirmed
1720
- ? `${packageName} is switching to the older-CPU binary for this machine.`
1721
- : `${packageName} crashed on startup; trying the older-CPU binary.`,
1926
+ cpuHasAvx2
1927
+ ? `${packageName} crashed, but this CPU supports AVX2; using the older-CPU binary until the next update.`
1928
+ : confirmed
1929
+ ? `${packageName} is switching to the older-CPU binary for this machine.`
1930
+ : `${packageName} crashed on startup; trying the older-CPU binary.`,
1722
1931
  )
1723
1932
 
1724
1933
  try {
@@ -1734,6 +1943,27 @@ function createLauncher(productConfig) {
1734
1943
  return true
1735
1944
  }
1736
1945
 
1946
+ /**
1947
+ * What the evidence says about AVX2 after a crash: `{ avx2, evidence }`,
1948
+ * avx2 null when nothing can tell. Bun's own verdict that AVX2 is missing
1949
+ * wins, then the OS probe, then avx2 in Bun's `CPU:` line.
1950
+ */
1951
+ function crashAvx2Verdict(code, signal, stderrTail) {
1952
+ if (
1953
+ stderrTail &&
1954
+ !(code === 0 && !signal) &&
1955
+ BUN_NO_AVX2_FEATURE.test(sanitizeForReplay(stderrTail))
1956
+ ) {
1957
+ return { avx2: false, evidence: 'bun-report' }
1958
+ }
1959
+ const probed = probeCpuAvx2()
1960
+ if (probed !== null) return { avx2: probed, evidence: cpuProbeSource() }
1961
+ if (stderrReportsAvx2Present(stderrTail)) {
1962
+ return { avx2: true, evidence: 'bun-report' }
1963
+ }
1964
+ return { avx2: null, evidence: null }
1965
+ }
1966
+
1737
1967
  function attachExitHandler(child, allowBaselineFallback = true) {
1738
1968
  const exitListener = async (code, signal) => {
1739
1969
  // A child we never watched (only reachable from a test) reports no age
@@ -1741,15 +1971,18 @@ function createLauncher(productConfig) {
1741
1971
  // as a startup crash and trigger a download.
1742
1972
  const msAlive = child.launch ? child.launch.msAlive() : Infinity
1743
1973
 
1974
+ // Any failed exit, not only a native crash code: a Bun crash on Windows
1975
+ // usually exits with plain code 3, and the reason is only in its stderr
1976
+ // (see stderrReportsMissingCpuFeature). Clean exits skip the wait.
1744
1977
  let stderrTail = ''
1745
- if (child.launch && (isWindowsNativeCrashCode(code) || signal)) {
1978
+ if (child.launch && (code !== 0 || signal)) {
1746
1979
  await child.launch.drained()
1747
1980
  stderrTail = child.launch.stderrTail()
1748
1981
  }
1749
1982
 
1750
1983
  if (
1751
1984
  allowBaselineFallback &&
1752
- (await tryFallbackToBaseline(code, signal, msAlive))
1985
+ (await tryFallbackToBaseline(code, signal, msAlive, stderrTail))
1753
1986
  ) {
1754
1987
  return
1755
1988
  }
@@ -1793,8 +2026,14 @@ function createLauncher(productConfig) {
1793
2026
  detectMachineHasAvx2,
1794
2027
  recordMachineLacksAvx2,
1795
2028
  readCachedAvx2,
2029
+ readCpuFeatureRecord,
2030
+ parseCpuinfoAvx2,
2031
+ parseSysctlAvx2,
2032
+ stderrReportsAvx2Present,
2033
+ getDownloadTargetKey,
1796
2034
  isIllegalInstructionExit,
1797
2035
  isStartupCpuFeatureCrash,
2036
+ stderrReportsMissingCpuFeature,
1798
2037
  tryFallbackToBaseline,
1799
2038
  printCrashDiagnostics,
1800
2039
  checkForUpdates,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freebuff",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "The world's strongest free coding agent",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -41,13 +41,13 @@
41
41
  "provenance": false
42
42
  },
43
43
  "binaryChecksums": {
44
- "linux-x64": "d23432f34ecbd4f14cbeb1e7f370bad058a03e30f0f65cbca431405cc6bb05ad",
45
- "linux-x64-baseline": "5ce3b598e49f500db1aa8577656600e8e6bc17a938b104290e47a23e5d605bca",
46
- "linux-arm64": "e697880ee488b5e6707f6d7dd65f60c03d14db65c455146d29c5c5ee62042b3a",
47
- "darwin-x64": "93557a697af5a9956e409f02937e4e247e93341754669f3d3dd1af85b42f18cb",
48
- "darwin-x64-baseline": "bd6b48ddfb5e4305855b87248eed25b9d0727d2cbea705cc5cc52b03494bd815",
49
- "darwin-arm64": "be1af482d5c96e0b28a54bb76936755c3928939251d31aa3fca55409353a3144",
50
- "win32-x64": "d7ce3ff20dab76f558a5f65d8f8f7a7c2b78b9f5e45f35889ef98ce86589afbd",
51
- "win32-x64-baseline": "18f9ce899d9e5d9ec1cb58445340e440db074ef7a8a0ae96fd1e58c0aea044a8"
44
+ "linux-x64": "02645c1354b0f72ae3ae6c138fd34b2f74afdf4552f17008713ff2f00f4af1ef",
45
+ "linux-x64-baseline": "5b758c46c3fb289fbd8ae04ce42c304a91e87a20ff5eab338e17cbc03e937831",
46
+ "linux-arm64": "9f40b2b4d76cacaa1f0d598cdfe3a5534e8f3e787803c604319dee569e08d923",
47
+ "darwin-x64": "ef2e71cd81b3166d6449e04221cc547a499bef90ba07c5087783650f63c72854",
48
+ "darwin-x64-baseline": "0d860e9b5cfb178f989fc5c23695d1c5f2328175683f2046775d59df77259f9c",
49
+ "darwin-arm64": "5c40f26c55f11b3395eae3d509ebbed9ffceaf1b06b929cfc90a4860cf64ac35",
50
+ "win32-x64": "826dd49fd9b412aaa87f023901a16872813832b84cda0bad0d97f14eb5ab63eb",
51
+ "win32-x64-baseline": "588cd19c2cdbfd9d323e1b1b737ae9e802404231293a2208a66494fc8ea93e5a"
52
52
  }
53
53
  }