diff --git a/install.sh b/install.sh index 9046a9bdf6..c7852c7539 100755 --- a/install.sh +++ b/install.sh @@ -572,7 +572,7 @@ fi BASE_PORT=8888 MAX_PORT_OFFSET=20 TIMEOUT_SEC=60 -POLL_INTERVAL_SEC=1 +POLL_INTERVAL_SEC=0.25 LOG_FILE="$DATA_DIR/studio.log" # why: in env-override mode multiple installs share an OS user; namespace the # lock and remember our own healthy port so we never attach to an unrelated @@ -727,9 +727,65 @@ _spawn_terminal() { _cmd="$1" _os=$(uname) if [ "$_os" = "Darwin" ]; then - # Escape backslashes and double-quotes for AppleScript string - _cmd_escaped=$(printf '%s' "$_cmd" | sed 's/\\/\\\\/g; s/"/\\"/g') - osascript -e "tell application \"Terminal\" to do script \"$_cmd_escaped\"" >/dev/null 2>&1 && return 0 + # AppleEvents are TCC-denied from unsigned .app bundles; spawn + # Terminal via a .command file + Launch Services instead. Server + # is nohup'd so warm relaunches hit the fast-path; watcher + trap + # in the .command couple Terminal close <-> server shutdown. + # `exec` keeps the recorded PID equal to the studio process so + # signals reach studio directly rather than a wrapper shell. + nohup sh -c "exec $_cmd" >> "$LOG_FILE" 2>&1 & + _server_pid=$! + _pid_file="$DATA_DIR/studio-$_launch_port.pid" + printf '%d\n' "$_server_pid" > "$_pid_file" 2>/dev/null || true + + _cmd_file="$DATA_DIR/launch-terminal.command" + _logfile_q=$(printf '%s' "$LOG_FILE" | sed "s/'/'\\\\''/g") + _pidfile_q=$(printf '%s' "$_pid_file" | sed "s/'/'\\\\''/g") + if { + { + printf '#!/bin/bash\n' + printf "SERVER_PID=%s\n" "$_server_pid" + printf "PID_FILE='%s'\n" "$_pidfile_q" + # Wait up to 12s for graceful shutdown before SIGKILL. + printf 'shutdown_studio() {\n' + printf ' kill -TERM "$SERVER_PID" 2>/dev/null\n' + printf ' _i=0\n' + printf ' while kill -0 "$SERVER_PID" 2>/dev/null && [ "$_i" -lt 24 ]; do\n' + printf ' sleep 0.5\n' + printf ' _i=$((_i + 1))\n' + printf ' done\n' + printf ' kill -0 "$SERVER_PID" 2>/dev/null && kill -KILL "$SERVER_PID" 2>/dev/null\n' + printf ' rm -f "$PID_FILE" 2>/dev/null\n' + printf '}\n' + printf "tail -n 100 -F '%s' &\n" "$_logfile_q" + printf 'TAIL_PID=$!\n' + # Server gone -> kill tail so bash exits cleanly. + printf '(\n' + printf ' while kill -0 "$SERVER_PID" 2>/dev/null; do sleep 1; done\n' + printf ' kill "$TAIL_PID" 2>/dev/null\n' + printf ') &\n' + printf 'WATCHER_PID=$!\n' + printf "trap 'shutdown_studio; kill \"\$WATCHER_PID\" \"\$TAIL_PID\" 2>/dev/null; exit' HUP INT TERM\n" + printf "trap 'rm -f \"\$PID_FILE\" 2>/dev/null' EXIT\n" + printf 'wait "$TAIL_PID" 2>/dev/null\n' + } > "$_cmd_file" 2>/dev/null \ + && chmod +x "$_cmd_file" 2>/dev/null \ + && open -a Terminal "$_cmd_file" 2>/dev/null + }; then + # Foreground Terminal (Launch Services spawns us backgrounded). + osascript -e 'tell application "Terminal" to activate' >/dev/null 2>&1 || true + return 0 + fi + # .command/open failed: kill orphan, fall through to generic fallback. + kill -TERM "$_server_pid" 2>/dev/null || true + _i=0 + while kill -0 "$_server_pid" 2>/dev/null && [ "$_i" -lt 6 ]; do + sleep 0.5 + _i=$((_i + 1)) + done + kill -0 "$_server_pid" 2>/dev/null && kill -KILL "$_server_pid" 2>/dev/null || true + rm -f "$_pid_file" 2>/dev/null || true + echo "[WARN] Could not open Terminal; falling back to background launch" >&2 else for _term in gnome-terminal konsole xfce4-terminal mate-terminal lxterminal xterm; do if command -v "$_term" >/dev/null 2>&1; then @@ -1005,6 +1061,17 @@ DESKTOP_EOF _css_contents="$_css_app/Contents" _css_macos_dir="$_css_contents/MacOS" _css_res_dir="$_css_contents/Resources" + # Recreate bundle if root or any subpath is a symlink (mkdir -p follows them). + if [ -L "$_css_app" ] || [ -L "$_css_contents" ] \ + || [ -L "$_css_macos_dir" ] || [ -L "$_css_res_dir" ]; then + rm -rf "$_css_app" 2>/dev/null || { + echo "[ERROR] $_css_app contains a symlinked bundle path; remove manually and re-run install" >&2 + return 1 + } + elif [ -e "$_css_app" ] && [ ! -d "$_css_app" ]; then + echo "[ERROR] $_css_app exists but is not a directory; remove manually and re-run install" >&2 + return 1 + fi mkdir -p "$_css_macos_dir" "$_css_res_dir" # Info.plist