@@ -39,13 +39,28 @@ _detect_theme() {
3939
4040 # 2. Query terminal background via OSC 11 (iTerm2, Ghostty, Kitty, WezTerm)
4141 if [[ -t 2 ]] && [[ -r /dev/tty ]]; then
42- local old_stty response=" "
42+ local old_stty response=" " _dd_pid _timer_pid
43+ local _dd_tmp
44+ _dd_tmp=$( mktemp)
4345 old_stty=$( stty -g < /dev/tty 2> /dev/null) || true
4446 stty raw -echo min 0 time 2 < /dev/tty 2> /dev/null
4547 printf ' \033]11;?\a' > /dev/tty 2> /dev/null
46- response=$( dd bs=1 count=30 < /dev/tty 2> /dev/null) || true
48+ # Read with kill-timer to prevent hang in non-standard terminals
49+ dd bs=1 count=30 < /dev/tty > " $_dd_tmp " 2> /dev/null &
50+ _dd_pid=$!
51+ (sleep 1 && kill " $_dd_pid " 2> /dev/null) &
52+ _timer_pid=$!
53+ wait " $_dd_pid " 2> /dev/null
54+ kill " $_timer_pid " 2> /dev/null; wait " $_timer_pid " 2> /dev/null
55+ response=$( cat " $_dd_tmp " )
56+ rm -f " $_dd_tmp "
4757 # Drain any leftover bytes from terminal response
48- dd bs=1 count=64 < /dev/tty > /dev/null 2>&1 || true
58+ dd bs=1 count=64 < /dev/tty > /dev/null 2>&1 &
59+ _dd_pid=$!
60+ (sleep 1 && kill " $_dd_pid " 2> /dev/null) &
61+ _timer_pid=$!
62+ wait " $_dd_pid " 2> /dev/null
63+ kill " $_timer_pid " 2> /dev/null; wait " $_timer_pid " 2> /dev/null
4964 stty " $old_stty " < /dev/tty 2> /dev/null
5065 if [[ " $response " =~ rgb:([0-9a-fA-F]+)/([0-9a-fA-F]+)/([0-9a-fA-F]+) ]]; then
5166 local r=$(( 16 #${BASH_REMATCH[1]: 0: 2} ))
@@ -130,10 +145,17 @@ spinner() {
130145run_with_spinner () {
131146 local msg=" $1 "
132147 shift
133- " $@ " & > /dev/null &
148+ local _rws_log
149+ _rws_log=$( mktemp)
150+ " $@ " & > " $_rws_log " &
134151 spinner $! " $msg "
135152 wait $! 2> /dev/null
136- return $?
153+ local rc=$?
154+ if [[ $rc -ne 0 ]]; then
155+ cat " $_rws_log " >&2
156+ fi
157+ rm -f " $_rws_log "
158+ return $rc
137159}
138160
139161# Progress bar — inline redraw
@@ -1056,15 +1078,16 @@ macrift_update() {
10561078 local tmp
10571079 tmp=" $( mktemp -d) "
10581080 if curl -fsSL " $MACRIFT_REPO_TAR " | tar -xz -C " $tmp " && [[ -d " $tmp /macrift-main" ]]; then
1059- rm -rf " $MACRIFT_DIR "
1081+ # Atomic swap: backup old → move new → remove backup
1082+ mv " $MACRIFT_DIR " " $MACRIFT_DIR .bak"
10601083 if mv " $tmp /macrift-main" " $MACRIFT_DIR " ; then
10611084 chmod +x " $MACRIFT_DIR /macrift.sh"
10621085 find " $MACRIFT_DIR " -name " *.sh" -exec chmod +x {} +
1086+ rm -rf " $MACRIFT_DIR .bak"
10631087 log_ok " Updated to $( cat " $MACRIFT_DIR /VERSION" 2> /dev/null || echo ' latest' ) "
10641088 else
10651089 log_err " Failed to replace install directory"
1066- # Restore from tmp if possible
1067- [[ -d " $tmp /macrift-main" ]] && mv " $tmp /macrift-main" " $MACRIFT_DIR "
1090+ mv " $MACRIFT_DIR .bak" " $MACRIFT_DIR "
10681091 rm -rf " $tmp "
10691092 return 1
10701093 fi
0 commit comments