codebuff 1.0.680 → 1.0.682
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 +195 -34
- package/package.json +1 -1
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,20 +307,35 @@ function streamToString(stream) {
|
|
|
214
307
|
|
|
215
308
|
function getCurrentVersion() {
|
|
216
309
|
try {
|
|
217
|
-
|
|
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
|
// Also verify the binary still exists
|
|
222
315
|
if (!fs.existsSync(CONFIG.binaryPath)) {
|
|
223
316
|
return null
|
|
224
317
|
}
|
|
318
|
+
const metadataTarget = metadata.target || getPlatformKey()
|
|
319
|
+
if (!isTargetAllowedForThisMachine(metadataTarget)) {
|
|
320
|
+
return null
|
|
321
|
+
}
|
|
225
322
|
return metadata.version || null
|
|
226
323
|
} catch (error) {
|
|
227
324
|
return null
|
|
228
325
|
}
|
|
229
326
|
}
|
|
230
327
|
|
|
328
|
+
function getCurrentMetadata() {
|
|
329
|
+
try {
|
|
330
|
+
if (!fs.existsSync(CONFIG.metadataPath)) {
|
|
331
|
+
return null
|
|
332
|
+
}
|
|
333
|
+
return JSON.parse(fs.readFileSync(CONFIG.metadataPath, 'utf8'))
|
|
334
|
+
} catch {
|
|
335
|
+
return null
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
231
339
|
function compareVersions(v1, v2) {
|
|
232
340
|
if (!v1 || !v2) return 0
|
|
233
341
|
|
|
@@ -306,13 +414,12 @@ function createProgressBar(percentage, width = 30) {
|
|
|
306
414
|
return '[' + '█'.repeat(filled) + '░'.repeat(empty) + ']'
|
|
307
415
|
}
|
|
308
416
|
|
|
309
|
-
async function downloadBinary(version) {
|
|
310
|
-
const
|
|
311
|
-
const fileName = PLATFORM_TARGETS[platformKey]
|
|
417
|
+
async function downloadBinary(version, targetKey = getDownloadTargetKey()) {
|
|
418
|
+
const fileName = PLATFORM_TARGETS[targetKey]
|
|
312
419
|
|
|
313
420
|
if (!fileName) {
|
|
314
421
|
const error = new Error(`Unsupported platform: ${process.platform} ${process.arch}`)
|
|
315
|
-
trackUpdateFailed(error.message, version, { stage: 'platform_check' })
|
|
422
|
+
trackUpdateFailed(error.message, version, { stage: 'platform_check', target: targetKey })
|
|
316
423
|
throw error
|
|
317
424
|
}
|
|
318
425
|
|
|
@@ -336,7 +443,7 @@ async function downloadBinary(version) {
|
|
|
336
443
|
if (res.statusCode !== 200) {
|
|
337
444
|
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
338
445
|
const error = new Error(`Download failed: HTTP ${res.statusCode}`)
|
|
339
|
-
trackUpdateFailed(error.message, version, { stage: 'http_download', statusCode: res.statusCode })
|
|
446
|
+
trackUpdateFailed(error.message, version, { stage: 'http_download', statusCode: res.statusCode, target: targetKey })
|
|
340
447
|
throw error
|
|
341
448
|
}
|
|
342
449
|
|
|
@@ -380,7 +487,7 @@ async function downloadBinary(version) {
|
|
|
380
487
|
const error = new Error(
|
|
381
488
|
`Binary not found after extraction. Expected: ${CONFIG.binaryName}, Available files: ${files.join(', ')}`,
|
|
382
489
|
)
|
|
383
|
-
trackUpdateFailed(error.message, version, { stage: 'extraction' })
|
|
490
|
+
trackUpdateFailed(error.message, version, { stage: 'extraction', target: targetKey })
|
|
384
491
|
throw error
|
|
385
492
|
}
|
|
386
493
|
|
|
@@ -434,7 +541,7 @@ async function downloadBinary(version) {
|
|
|
434
541
|
// Save version metadata for fast version checking
|
|
435
542
|
fs.writeFileSync(
|
|
436
543
|
CONFIG.metadataPath,
|
|
437
|
-
JSON.stringify({ version }, null, 2),
|
|
544
|
+
JSON.stringify({ version, target: targetKey }, null, 2),
|
|
438
545
|
)
|
|
439
546
|
} finally {
|
|
440
547
|
// Clean up temp directory even if rename fails
|
|
@@ -518,14 +625,7 @@ async function checkForUpdates(runningProcess, exitListener) {
|
|
|
518
625
|
await downloadBinary(latestVersion)
|
|
519
626
|
|
|
520
627
|
const newChild = spawnInstalledBinary({ detached: false })
|
|
521
|
-
|
|
522
|
-
newChild.on('exit', (code, signal) => {
|
|
523
|
-
resetTerminal({
|
|
524
|
-
exitAlternateScreen: shouldExitAlternateScreen(code, signal),
|
|
525
|
-
})
|
|
526
|
-
printCrashDiagnostics(code, signal)
|
|
527
|
-
process.exit(signal ? 1 : (code || 0))
|
|
528
|
-
})
|
|
628
|
+
attachExitHandler(newChild)
|
|
529
629
|
|
|
530
630
|
return new Promise(() => {})
|
|
531
631
|
}
|
|
@@ -537,9 +637,7 @@ async function checkForUpdates(runningProcess, exitListener) {
|
|
|
537
637
|
function printCrashDiagnostics(code, signal) {
|
|
538
638
|
// Windows NTSTATUS codes (unsigned DWORD)
|
|
539
639
|
const unsignedCode = getUnsignedExitCode(code)
|
|
540
|
-
const isIllegalInstruction =
|
|
541
|
-
signal === 'SIGILL' ||
|
|
542
|
-
(process.platform === 'win32' && unsignedCode === 0xC000001D)
|
|
640
|
+
const isIllegalInstruction = isIllegalInstructionExit(code, signal)
|
|
543
641
|
const isAccessViolation =
|
|
544
642
|
signal === 'SIGSEGV' ||
|
|
545
643
|
(process.platform === 'win32' && unsignedCode === 0xC0000005)
|
|
@@ -620,6 +718,11 @@ function printSpawnFailure(err) {
|
|
|
620
718
|
console.error('')
|
|
621
719
|
}
|
|
622
720
|
|
|
721
|
+
function exitOnSpawnFailure(err) {
|
|
722
|
+
printSpawnFailure(err)
|
|
723
|
+
process.exit(1)
|
|
724
|
+
}
|
|
725
|
+
|
|
623
726
|
function spawnInstalledBinary(options = {}) {
|
|
624
727
|
if (!fs.existsSync(CONFIG.binaryPath)) {
|
|
625
728
|
try {
|
|
@@ -631,29 +734,79 @@ function spawnInstalledBinary(options = {}) {
|
|
|
631
734
|
`downloaded binary is missing at ${CONFIG.binaryPath}`,
|
|
632
735
|
)
|
|
633
736
|
error.code = 'BINARY_MISSING'
|
|
634
|
-
|
|
635
|
-
process.exit(1)
|
|
737
|
+
exitOnSpawnFailure(error)
|
|
636
738
|
}
|
|
637
739
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
740
|
+
// spawn() only emits 'error' asynchronously for a few errno values
|
|
741
|
+
// (EACCES, EAGAIN, EMFILE, ENFILE, ENOENT); everything else — notably
|
|
742
|
+
// UNKNOWN on Windows when antivirus or Smart App Control blocks the
|
|
743
|
+
// exe or the download is corrupt — is thrown synchronously.
|
|
744
|
+
let child
|
|
745
|
+
try {
|
|
746
|
+
child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
|
|
747
|
+
stdio: 'inherit',
|
|
748
|
+
...options,
|
|
749
|
+
})
|
|
750
|
+
} catch (err) {
|
|
751
|
+
exitOnSpawnFailure(err)
|
|
752
|
+
}
|
|
642
753
|
|
|
643
|
-
child.on('error',
|
|
644
|
-
printSpawnFailure(err)
|
|
645
|
-
process.exit(1)
|
|
646
|
-
})
|
|
754
|
+
child.on('error', exitOnSpawnFailure)
|
|
647
755
|
|
|
648
756
|
return child
|
|
649
757
|
}
|
|
650
758
|
|
|
651
|
-
async function
|
|
652
|
-
|
|
759
|
+
async function tryFallbackToBaseline(code, signal) {
|
|
760
|
+
if (!isIllegalInstructionExit(code, signal)) {
|
|
761
|
+
return false
|
|
762
|
+
}
|
|
653
763
|
|
|
654
|
-
const
|
|
764
|
+
const fallbackTarget = getBaselineFallbackTargetKey()
|
|
765
|
+
if (!fallbackTarget) {
|
|
766
|
+
return false
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
const metadata = getCurrentMetadata()
|
|
770
|
+
const currentTarget = metadata?.target || getDefaultTargetKey()
|
|
771
|
+
if (currentTarget === fallbackTarget) {
|
|
772
|
+
return false
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
const version = metadata?.version || (await getLatestVersion())
|
|
776
|
+
if (!version) {
|
|
777
|
+
return false
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
resetTerminal({
|
|
781
|
+
exitAlternateScreen: shouldExitAlternateScreen(code, signal),
|
|
782
|
+
})
|
|
783
|
+
console.error('')
|
|
784
|
+
console.error(
|
|
785
|
+
`${packageName} is switching to the older-CPU binary for this machine.`,
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
try {
|
|
789
|
+
await downloadBinary(version, fallbackTarget)
|
|
790
|
+
} catch (error) {
|
|
791
|
+
term.clearLine()
|
|
792
|
+
console.error(`Failed to download ${fallbackTarget}: ${error.message}`)
|
|
793
|
+
return false
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
const child = spawnInstalledBinary({ detached: false })
|
|
797
|
+
attachExitHandler(child, false)
|
|
798
|
+
return true
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function attachExitHandler(child, allowBaselineFallback = true) {
|
|
802
|
+
const exitListener = async (code, signal) => {
|
|
803
|
+
if (
|
|
804
|
+
allowBaselineFallback &&
|
|
805
|
+
(await tryFallbackToBaseline(code, signal))
|
|
806
|
+
) {
|
|
807
|
+
return
|
|
808
|
+
}
|
|
655
809
|
|
|
656
|
-
const exitListener = (code, signal) => {
|
|
657
810
|
resetTerminal({
|
|
658
811
|
exitAlternateScreen: shouldExitAlternateScreen(code, signal),
|
|
659
812
|
})
|
|
@@ -662,6 +815,14 @@ async function main() {
|
|
|
662
815
|
}
|
|
663
816
|
|
|
664
817
|
child.on('exit', exitListener)
|
|
818
|
+
return exitListener
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
async function main() {
|
|
822
|
+
await ensureBinaryExists()
|
|
823
|
+
|
|
824
|
+
const child = spawnInstalledBinary()
|
|
825
|
+
const exitListener = attachExitHandler(child)
|
|
665
826
|
|
|
666
827
|
setTimeout(() => {
|
|
667
828
|
checkForUpdates(child, exitListener)
|