MCPcopy
hub / github.com/codeaashu/claude-code / updateSymlink

Function updateSymlink

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

Source from the content-addressed store, hash-verified

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

Callers 1

performVersionUpdateFunction · 0.85

Calls 9

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

Tested by

no test coverage detected