MCPcopy Create free account
hub / github.com/claude-code-best/claude-code / updateSymlink

Function updateSymlink

src/utils/nativeInstaller/installer.ts:636–795  ·  view source on GitHub ↗
(
  symlinkPath: string,
  targetPath: string,
)

Source from the content-addressed store, hash-verified

634}
635
636async function updateSymlink(
637 symlinkPath: string,
638 targetPath: string,
639): Promise<boolean> {
640 const platform = getPlatform()
641 const isWindows = platform.startsWith('win32')
642
643 // On Windows, directly copy the executable instead of creating a symlink
644 if (isWindows) {
645 try {
646 // Ensure parent directory exists
647 const parentDir = dirname(symlinkPath)
648 await mkdir(parentDir, { recursive: true })
649
650 // Check if file already exists and has same content
651 let existingStats: Stats | undefined
652 try {
653 existingStats = await stat(symlinkPath)
654 } catch {
655 // symlinkPath doesn't exist
656 }
657
658 if (existingStats) {
659 try {
660 const targetStats = await stat(targetPath)
661 // If sizes match, assume files are the same (avoid reading large files)
662 if (existingStats.size === targetStats.size) {
663 return false
664 }
665 } catch {
666 // Continue with copy if we can't compare
667 }
668 // Use rename strategy to handle file locking on Windows
669 // Rename always works even for running executables, unlike delete
670 const oldFileName = `${symlinkPath}.old.${Date.now()}`
671 await rename(symlinkPath, oldFileName)
672
673 // Try to copy new executable, with rollback on failure
674 try {
675 await copyFile(targetPath, symlinkPath)
676 // Success - try immediate cleanup of old file (non-blocking)
677 try {
678 await unlink(oldFileName)
679 } catch {
680 // File still running - ignore, Windows will clean up eventually
681 }
682 } catch (copyError) {
683 // Copy failed - restore the old executable
684 try {
685 await rename(oldFileName, symlinkPath)
686 } catch (restoreError) {
687 // Critical: User left without working executable - prioritize restore error
688 const errorWithCause = new Error(
689 `Failed to restore old executable: ${restoreError}`,
690 { cause: copyError },
691 )
692 logError(errorWithCause)
693 throw errorWithCause

Callers 1

performVersionUpdateFunction · 0.85

Calls 10

getPlatformFunction · 0.85
mkdirFunction · 0.85
statFunction · 0.85
renameFunction · 0.85
unlinkFunction · 0.85
isENOENTFunction · 0.85
nowMethod · 0.80
logErrorFunction · 0.50
logForDebuggingFunction · 0.50
resolveFunction · 0.50

Tested by

no test coverage detected