codebuff 1.0.678 → 1.0.679
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 +108 -26
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -17,11 +17,9 @@ const packageName = 'codebuff'
|
|
|
17
17
|
* Terminal escape sequences to reset terminal state after the child process exits.
|
|
18
18
|
* When the binary is SIGKILL'd, it can't clean up its own terminal state.
|
|
19
19
|
* The wrapper (this process) survives and must reset these modes.
|
|
20
|
-
*
|
|
21
|
-
* Keep in sync with TERMINAL_RESET_SEQUENCES in cli/src/utils/renderer-cleanup.ts
|
|
22
20
|
*/
|
|
23
|
-
const
|
|
24
|
-
|
|
21
|
+
const EXIT_ALTERNATE_SCREEN_SEQUENCE = '\x1b[?1049l'
|
|
22
|
+
const SAFE_TERMINAL_RESET_SEQUENCES =
|
|
25
23
|
'\x1b[?1000l' + // Disable X10 mouse mode
|
|
26
24
|
'\x1b[?1002l' + // Disable button event mouse mode
|
|
27
25
|
'\x1b[?1003l' + // Disable any-event mouse mode (all motion)
|
|
@@ -30,7 +28,12 @@ const TERMINAL_RESET_SEQUENCES =
|
|
|
30
28
|
'\x1b[?2004l' + // Disable bracketed paste mode
|
|
31
29
|
'\x1b[?25h' // Show cursor
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
const FULL_TERMINAL_RESET_SEQUENCES =
|
|
32
|
+
EXIT_ALTERNATE_SCREEN_SEQUENCE + SAFE_TERMINAL_RESET_SEQUENCES
|
|
33
|
+
|
|
34
|
+
function resetTerminal(options = {}) {
|
|
35
|
+
const { exitAlternateScreen = false } = options
|
|
36
|
+
|
|
34
37
|
try {
|
|
35
38
|
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
36
39
|
process.stdin.setRawMode(false)
|
|
@@ -40,13 +43,37 @@ function resetTerminal() {
|
|
|
40
43
|
}
|
|
41
44
|
try {
|
|
42
45
|
if (process.stdout.isTTY) {
|
|
43
|
-
|
|
46
|
+
// Exiting the alternate screen is only safe after an interactive child.
|
|
47
|
+
// Plain CLI paths like --help never enter it, and ?1049l can erase output.
|
|
48
|
+
process.stdout.write(
|
|
49
|
+
exitAlternateScreen
|
|
50
|
+
? FULL_TERMINAL_RESET_SEQUENCES
|
|
51
|
+
: SAFE_TERMINAL_RESET_SEQUENCES,
|
|
52
|
+
)
|
|
44
53
|
}
|
|
45
54
|
} catch {
|
|
46
55
|
// stdout may be closed
|
|
47
56
|
}
|
|
48
57
|
}
|
|
49
58
|
|
|
59
|
+
function getUnsignedExitCode(code) {
|
|
60
|
+
return code != null && code < 0 ? (code >>> 0) : code
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isWindowsNativeCrashCode(code) {
|
|
64
|
+
const unsignedCode = getUnsignedExitCode(code)
|
|
65
|
+
return (
|
|
66
|
+
process.platform === 'win32' &&
|
|
67
|
+
(unsignedCode === 0xC000001D ||
|
|
68
|
+
unsignedCode === 0xC0000005 ||
|
|
69
|
+
unsignedCode === 0xC0000409)
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function shouldExitAlternateScreen(code, signal) {
|
|
74
|
+
return Boolean(signal) || isWindowsNativeCrashCode(code)
|
|
75
|
+
}
|
|
76
|
+
|
|
50
77
|
function createConfig(packageName) {
|
|
51
78
|
const homeDir = os.homedir()
|
|
52
79
|
const configDir = path.join(homeDir, '.config', 'manicode')
|
|
@@ -485,27 +512,21 @@ async function checkForUpdates(runningProcess, exitListener) {
|
|
|
485
512
|
}, 5000)
|
|
486
513
|
})
|
|
487
514
|
|
|
488
|
-
resetTerminal()
|
|
515
|
+
resetTerminal({ exitAlternateScreen: true })
|
|
489
516
|
console.log(`Update available: ${currentVersion} → ${latestVersion}`)
|
|
490
517
|
|
|
491
518
|
await downloadBinary(latestVersion)
|
|
492
519
|
|
|
493
|
-
const newChild =
|
|
494
|
-
stdio: 'inherit',
|
|
495
|
-
detached: false,
|
|
496
|
-
})
|
|
520
|
+
const newChild = spawnInstalledBinary({ detached: false })
|
|
497
521
|
|
|
498
522
|
newChild.on('exit', (code, signal) => {
|
|
499
|
-
resetTerminal(
|
|
523
|
+
resetTerminal({
|
|
524
|
+
exitAlternateScreen: shouldExitAlternateScreen(code, signal),
|
|
525
|
+
})
|
|
500
526
|
printCrashDiagnostics(code, signal)
|
|
501
527
|
process.exit(signal ? 1 : (code || 0))
|
|
502
528
|
})
|
|
503
529
|
|
|
504
|
-
newChild.on('error', (err) => {
|
|
505
|
-
console.error('Failed to start codebuff:', err.message)
|
|
506
|
-
process.exit(1)
|
|
507
|
-
})
|
|
508
|
-
|
|
509
530
|
return new Promise(() => {})
|
|
510
531
|
}
|
|
511
532
|
} catch (error) {
|
|
@@ -515,7 +536,7 @@ async function checkForUpdates(runningProcess, exitListener) {
|
|
|
515
536
|
|
|
516
537
|
function printCrashDiagnostics(code, signal) {
|
|
517
538
|
// Windows NTSTATUS codes (unsigned DWORD)
|
|
518
|
-
const unsignedCode =
|
|
539
|
+
const unsignedCode = getUnsignedExitCode(code)
|
|
519
540
|
const isIllegalInstruction =
|
|
520
541
|
signal === 'SIGILL' ||
|
|
521
542
|
(process.platform === 'win32' && unsignedCode === 0xC000001D)
|
|
@@ -561,26 +582,87 @@ function printCrashDiagnostics(code, signal) {
|
|
|
561
582
|
console.error('')
|
|
562
583
|
}
|
|
563
584
|
|
|
564
|
-
|
|
565
|
-
|
|
585
|
+
function getInstalledBinaryStatus() {
|
|
586
|
+
try {
|
|
587
|
+
const stats = fs.statSync(CONFIG.binaryPath)
|
|
588
|
+
return stats.isFile() ? `yes (${formatBytes(stats.size)})` : 'no'
|
|
589
|
+
} catch {
|
|
590
|
+
return 'no'
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function printSpawnFailure(err) {
|
|
595
|
+
resetTerminal()
|
|
596
|
+
const code = err && err.code ? ` (${err.code})` : ''
|
|
597
|
+
|
|
598
|
+
console.error(`Failed to start ${packageName}: ${err.message}${code}`)
|
|
599
|
+
console.error('')
|
|
600
|
+
console.error('System info:')
|
|
601
|
+
console.error(` Platform: ${process.platform} ${process.arch}`)
|
|
602
|
+
console.error(` Node: ${process.version}`)
|
|
603
|
+
console.error(` Binary: ${CONFIG.binaryPath}`)
|
|
604
|
+
console.error(` Exists: ${getInstalledBinaryStatus()}`)
|
|
605
|
+
|
|
606
|
+
if (process.platform === 'win32') {
|
|
607
|
+
console.error('')
|
|
608
|
+
console.error(
|
|
609
|
+
'On Windows, this can happen when Windows Security or antivirus blocks',
|
|
610
|
+
)
|
|
611
|
+
console.error(
|
|
612
|
+
'or quarantines the downloaded executable, or when the binary requires',
|
|
613
|
+
)
|
|
614
|
+
console.error('CPU instructions that are not available on this machine.')
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
console.error('')
|
|
618
|
+
console.error('Try deleting the downloaded files and running again:')
|
|
619
|
+
console.error(` ${CONFIG.configDir}`)
|
|
620
|
+
console.error('')
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function spawnInstalledBinary(options = {}) {
|
|
624
|
+
if (!fs.existsSync(CONFIG.binaryPath)) {
|
|
625
|
+
try {
|
|
626
|
+
if (fs.existsSync(CONFIG.metadataPath)) fs.unlinkSync(CONFIG.metadataPath)
|
|
627
|
+
} catch {
|
|
628
|
+
// best effort
|
|
629
|
+
}
|
|
630
|
+
const error = new Error(
|
|
631
|
+
`downloaded binary is missing at ${CONFIG.binaryPath}`,
|
|
632
|
+
)
|
|
633
|
+
error.code = 'BINARY_MISSING'
|
|
634
|
+
printSpawnFailure(error)
|
|
635
|
+
process.exit(1)
|
|
636
|
+
}
|
|
566
637
|
|
|
567
638
|
const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
|
|
568
639
|
stdio: 'inherit',
|
|
640
|
+
...options,
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
child.on('error', (err) => {
|
|
644
|
+
printSpawnFailure(err)
|
|
645
|
+
process.exit(1)
|
|
569
646
|
})
|
|
570
647
|
|
|
648
|
+
return child
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
async function main() {
|
|
652
|
+
await ensureBinaryExists()
|
|
653
|
+
|
|
654
|
+
const child = spawnInstalledBinary()
|
|
655
|
+
|
|
571
656
|
const exitListener = (code, signal) => {
|
|
572
|
-
resetTerminal(
|
|
657
|
+
resetTerminal({
|
|
658
|
+
exitAlternateScreen: shouldExitAlternateScreen(code, signal),
|
|
659
|
+
})
|
|
573
660
|
printCrashDiagnostics(code, signal)
|
|
574
661
|
process.exit(signal ? 1 : (code || 0))
|
|
575
662
|
}
|
|
576
663
|
|
|
577
664
|
child.on('exit', exitListener)
|
|
578
665
|
|
|
579
|
-
child.on('error', (err) => {
|
|
580
|
-
console.error('Failed to start codebuff:', err.message)
|
|
581
|
-
process.exit(1)
|
|
582
|
-
})
|
|
583
|
-
|
|
584
666
|
setTimeout(() => {
|
|
585
667
|
checkForUpdates(child, exitListener)
|
|
586
668
|
}, 100)
|