Files
DeskClaw/scripts/installer.nsh
2026-03-09 19:03:06 +08:00

155 lines
5.5 KiB
NSIS

; ClawX Custom NSIS Installer/Uninstaller Script
;
; Install: enables long paths, adds resources\cli to user PATH for openclaw CLI.
; Uninstall: removes the PATH entry and optionally deletes user data.
!ifndef nsProcess::FindProcess
!include "nsProcess.nsh"
!endif
!macro customCheckAppRunning
; Pre-emptively remove old shortcuts to prevent the Windows "Missing Shortcut"
; dialog during upgrades. The built-in NSIS uninstaller deletes ClawX.exe
; *before* removing shortcuts; Windows Shell link tracking can detect the
; broken target in that brief window and pop a resolver dialog.
; Delete is a silent no-op when the file doesn't exist (safe for fresh installs).
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}.lnk"
${nsProcess::FindProcess} "${APP_EXECUTABLE_FILENAME}" $R0
${if} $R0 == 0
${if} ${isUpdated}
# allow app to exit without explicit kill
Sleep 1000
Goto doStopProcess
${endIf}
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "$(appRunning)" /SD IDOK IDOK doStopProcess
Quit
doStopProcess:
DetailPrint `Closing running "${PRODUCT_NAME}"...`
# Silently kill the process using nsProcess instead of taskkill / cmd.exe
${nsProcess::KillProcess} "${APP_EXECUTABLE_FILENAME}" $R0
# to ensure that files are not "in-use"
Sleep 300
# Retry counter
StrCpy $R1 0
loop:
IntOp $R1 $R1 + 1
${nsProcess::FindProcess} "${APP_EXECUTABLE_FILENAME}" $R0
${if} $R0 == 0
# wait to give a chance to exit gracefully
Sleep 1000
${nsProcess::KillProcess} "${APP_EXECUTABLE_FILENAME}" $R0
${nsProcess::FindProcess} "${APP_EXECUTABLE_FILENAME}" $R0
${If} $R0 == 0
DetailPrint `Waiting for "${PRODUCT_NAME}" to close.`
Sleep 2000
${else}
Goto not_running
${endIf}
${else}
Goto not_running
${endIf}
# App likely running with elevated permissions.
# Ask user to close it manually
${if} $R1 > 1
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "$(appCannotBeClosed)" /SD IDCANCEL IDRETRY loop
Quit
${else}
Goto loop
${endIf}
not_running:
${nsProcess::Unload}
${endIf}
!macroend
!macro customInstall
; Enable Windows long path support (Windows 10 1607+ / Windows 11).
; pnpm virtual store paths can exceed the default MAX_PATH limit of 260 chars.
; Writing to HKLM requires admin privileges; on per-user installs without
; elevation this call silently fails — no crash, just no key written.
WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1
; Use PowerShell to update the current user's PATH.
; This avoids NSIS string-buffer limits and preserves long PATH values.
InitPluginsDir
ClearErrors
File "/oname=$PLUGINSDIR\update-user-path.ps1" "${PROJECT_DIR}\resources\cli\win32\update-user-path.ps1"
nsExec::ExecToStack '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$PLUGINSDIR\update-user-path.ps1" -Action add -CliDir "$INSTDIR\resources\cli"'
Pop $0
Pop $1
StrCmp $0 "error" 0 +2
DetailPrint "Warning: Failed to launch PowerShell while updating PATH."
StrCmp $0 "timeout" 0 +2
DetailPrint "Warning: PowerShell PATH update timed out."
StrCmp $0 "0" 0 +2
Goto _ci_done
DetailPrint "Warning: PowerShell PATH update exited with code $0."
_ci_done:
!macroend
!macro customUnInstall
; Remove resources\cli from user PATH via PowerShell so long PATH values are handled safely
InitPluginsDir
ClearErrors
File "/oname=$PLUGINSDIR\update-user-path.ps1" "${PROJECT_DIR}\resources\cli\win32\update-user-path.ps1"
nsExec::ExecToStack '"$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$PLUGINSDIR\update-user-path.ps1" -Action remove -CliDir "$INSTDIR\resources\cli"'
Pop $0
Pop $1
StrCmp $0 "error" 0 +2
DetailPrint "Warning: Failed to launch PowerShell while removing PATH entry."
StrCmp $0 "timeout" 0 +2
DetailPrint "Warning: PowerShell PATH removal timed out."
StrCmp $0 "0" 0 +2
Goto _cu_pathDone
DetailPrint "Warning: PowerShell PATH removal exited with code $0."
_cu_pathDone:
; Ask user if they want to completely remove all user data
MessageBox MB_YESNO|MB_ICONQUESTION \
"Do you want to completely remove all ClawX user data?$\r$\n$\r$\nThis will delete:$\r$\n • .openclaw folder (configuration & skills)$\r$\n • AppData\Local\clawx (local app data)$\r$\n • AppData\Roaming\clawx (roaming app data)$\r$\n$\r$\nSelect 'No' to keep your data for future reinstallation." \
/SD IDNO IDYES _cu_removeData IDNO _cu_skipRemove
_cu_removeData:
; --- Always remove current user's data first ---
RMDir /r "$PROFILE\.openclaw"
RMDir /r "$LOCALAPPDATA\clawx"
RMDir /r "$APPDATA\clawx"
; --- For per-machine (all users) installs, enumerate all user profiles ---
StrCpy $R0 0
_cu_enumLoop:
EnumRegKey $R1 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $R0
StrCmp $R1 "" _cu_enumDone
ReadRegStr $R2 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$R1" "ProfileImagePath"
StrCmp $R2 "" _cu_enumNext
ExpandEnvStrings $R2 $R2
StrCmp $R2 $PROFILE _cu_enumNext
RMDir /r "$R2\.openclaw"
RMDir /r "$R2\AppData\Local\clawx"
RMDir /r "$R2\AppData\Roaming\clawx"
_cu_enumNext:
IntOp $R0 $R0 + 1
Goto _cu_enumLoop
_cu_enumDone:
_cu_skipRemove:
!macroend