#!/usr/bin/env bash # Capture one-shot macOS launch diagnostics for a published Orca release. # # Usage: # ORCA_DIAGNOSTIC_TAG=v1.4.42-rc.1 bash config/scripts/macos-launch-diagnostics.sh # bash config/scripts/macos-launch-diagnostics.sh --tag v1.4.42-rc.1 set -euo pipefail REPO="${ORCA_DIAGNOSTIC_REPO:-stablyai/orca}" TAG="${ORCA_DIAGNOSTIC_TAG:-}" KEEP=0 while [[ $# -gt 0 ]]; do case "$1" in --tag) TAG="${2:-}" shift 2 ;; --repo) REPO="${2:-}" shift 2 ;; --keep) KEEP=1 shift ;; -h|--help) cat <<'EOF' Capture one-shot macOS launch diagnostics for a published Orca release. Usage: ORCA_DIAGNOSTIC_TAG=v1.4.42-rc.1 bash config/scripts/macos-launch-diagnostics.sh bash config/scripts/macos-launch-diagnostics.sh --tag v1.4.42-rc.1 EOF exit 0 ;; *) echo "Unknown argument: $1" >&2 echo "Usage: $0 --tag vX.Y.Z-rc.N [--repo owner/repo] [--keep]" >&2 exit 2 ;; esac done if [[ "$(uname -s)" != "Darwin" ]]; then echo "This diagnostic script only supports macOS." >&2 exit 2 fi if [[ -z "$TAG" ]]; then echo "Set ORCA_DIAGNOSTIC_TAG or pass --tag vX.Y.Z-rc.N." >&2 exit 2 fi ARCH="$(uname -m)" case "$ARCH" in arm64) ASSET="orca-macos-arm64.dmg" ;; x86_64) ASSET="orca-macos-x64.dmg" ;; *) echo "Unsupported macOS architecture: $ARCH" >&2 exit 2 ;; esac TIMESTAMP="$(date -u '+%Y%m%dT%H%M%SZ')" WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/orca-launch-diagnostics.XXXXXXXX")" OUT_DIR="$WORK_DIR/output" MOUNT_DIR="$WORK_DIR/mount" APP_DIR="$WORK_DIR/Orca.app" DMG_PATH="$WORK_DIR/$ASSET" mkdir -p "$OUT_DIR" "$MOUNT_DIR" if [[ -d "$HOME/Desktop" ]]; then ZIP_PATH="$HOME/Desktop/orca-launch-diagnostics-${TAG}-${TIMESTAMP}.zip" else ZIP_PATH="$PWD/orca-launch-diagnostics-${TAG}-${TIMESTAMP}.zip" fi diag_log() { printf '[orca-diagnostics] %s\n' "$*" } run_capture() { local name="$1" shift { echo "\$ $*" "$@" } >"$OUT_DIR/$name.out" 2>"$OUT_DIR/$name.err" || { local code=$? echo "exit=$code" >>"$OUT_DIR/$name.err" return 0 } } cleanup() { if mount | grep -F " on $MOUNT_DIR " >/dev/null 2>&1; then hdiutil detach "$MOUNT_DIR" -quiet >/dev/null 2>&1 || true fi if [[ "$KEEP" -eq 0 ]]; then rm -rf "$WORK_DIR" else diag_log "kept working directory: $WORK_DIR" fi } trap cleanup EXIT write_environment_report() { { echo "tag=$TAG" echo "repo=$REPO" echo "asset=$ASSET" echo "timestamp_utc=$TIMESTAMP" echo echo "## sw_vers" sw_vers || true echo echo "## uname" uname -a || true echo echo "## shell" echo "$SHELL" echo echo "## current Orca processes before diagnostics" pgrep -fl 'Orca|orca' || true } >"$OUT_DIR/environment.txt" } ensure_no_existing_orca() { local existing existing="$(pgrep -x Orca || true)" if [[ -z "$existing" ]]; then return 0 fi { echo "An Orca process is already running. Close Orca and run this script again." echo ps -p "$(printf '%s' "$existing" | paste -sd, -)" -o pid=,ppid=,command= || true } | tee "$OUT_DIR/existing-orca-process.txt" >&2 exit 2 } download_and_copy_app() { local url="https://github.com/$REPO/releases/download/$TAG/$ASSET" diag_log "downloading $url" curl -fL --retry 3 --retry-delay 2 -o "$DMG_PATH" "$url" shasum -a 256 "$DMG_PATH" >"$OUT_DIR/dmg.sha256" || true diag_log "mounting DMG" hdiutil attach "$DMG_PATH" -nobrowse -readonly -mountpoint "$MOUNT_DIR" >"$OUT_DIR/hdiutil-attach.txt" local source_app source_app="$(find "$MOUNT_DIR" -maxdepth 1 -name '*.app' -type d | head -n 1)" if [[ -z "$source_app" ]]; then echo "No .app bundle found in $DMG_PATH" >&2 exit 1 fi diag_log "copying app to isolated temp path" ditto "$source_app" "$APP_DIR" hdiutil detach "$MOUNT_DIR" -quiet } write_app_report() { { echo "app=$APP_DIR" echo echo "## Info.plist" plutil -p "$APP_DIR/Contents/Info.plist" || true echo echo "## spctl" spctl -a -vvv "$APP_DIR" || true echo echo "## codesign display" codesign -dv --verbose=4 "$APP_DIR" || true echo echo "## codesign verify" codesign --verify --strict --deep "$APP_DIR" || true echo echo "## xattr" xattr -lr "$APP_DIR" || true echo echo "## native modules" find "$APP_DIR/Contents/Resources" -name '*.node' -print || true } >"$OUT_DIR/app-report.txt" 2>&1 } start_log_stream() { local file="$1" local predicate='process == "Orca" OR eventMessage CONTAINS[c] "Orca" OR eventMessage CONTAINS[c] "com.stablyai.orca"' if command -v log >/dev/null 2>&1; then command log stream --style compact --predicate "$predicate" >"$file" 2>&1 & echo "$!" else echo "" fi } stop_log_stream() { local pid="$1" if [[ -n "$pid" ]] && kill -0 "$pid" >/dev/null 2>&1; then kill "$pid" >/dev/null 2>&1 || true wait "$pid" >/dev/null 2>&1 || true fi } latest_orca_pid_for_app() { pgrep -nf "$APP_DIR/Contents/MacOS/Orca" || true } sample_process_once() { local pid="$1" local file="$2" if [[ -n "$pid" ]] && command -v sample >/dev/null 2>&1; then sample "$pid" 1 -file "$file" >"$file.command.out" 2>"$file.command.err" || true fi } terminate_app_processes() { local pid pid="$(latest_orca_pid_for_app)" if [[ -n "$pid" ]]; then kill "$pid" >/dev/null 2>&1 || true sleep 1 if kill -0 "$pid" >/dev/null 2>&1; then kill -9 "$pid" >/dev/null 2>&1 || true fi fi } wait_for_probe() { local runner_pid="$1" local label="$2" local sample_file="$OUT_DIR/$label.sample.txt" local sampled=0 local i for i in $(seq 1 200); do local app_pid app_pid="$(latest_orca_pid_for_app)" if [[ "$sampled" -eq 0 && -n "$app_pid" ]]; then sampled=1 echo "sampled_pid=$app_pid" >>"$OUT_DIR/$label.meta" sample_process_once "$app_pid" "$sample_file" fi if ! kill -0 "$runner_pid" >/dev/null 2>&1; then set +e wait "$runner_pid" local runner_exit=$? set -e echo "runner_exit=$runner_exit" >>"$OUT_DIR/$label.meta" return 0 fi sleep 0.1 done echo "runner_timeout_after_seconds=20" >>"$OUT_DIR/$label.meta" terminate_app_processes wait "$runner_pid" >/dev/null 2>&1 || true } run_launchservices_probe() { local label="$1" local extra_env_name="${2:-}" local extra_env_value="${3:-}" local stderr_file="$OUT_DIR/$label.stderr.log" local stdout_file="$OUT_DIR/$label.stdout.log" local bootstrap_file="$OUT_DIR/$label.bootstrap.log" local stream_file="$OUT_DIR/$label.system-stream.log" local stream_pid diag_log "running LaunchServices probe: $label" stream_pid="$(start_log_stream "$stream_file")" { echo "label=$label" echo "started_utc=$(date -u '+%Y-%m-%dT%H:%M:%SZ')" echo "bootstrap_file=$bootstrap_file" [[ -n "$extra_env_name" ]] && echo "$extra_env_name=$extra_env_value" } >"$OUT_DIR/$label.meta" if [[ -n "$extra_env_name" ]]; then open -n -W \ --stdout "$stdout_file" \ --stderr "$stderr_file" \ --env ELECTRON_ENABLE_LOGGING=1 \ --env ORCA_STARTUP_DIAGNOSTICS=trace \ --env ORCA_STARTUP_DIAGNOSTICS_TRACE_LIMIT=30000 \ --env ORCA_STARTUP_DIAGNOSTICS_FILE="$bootstrap_file" \ --env "$extra_env_name=$extra_env_value" \ "$APP_DIR" & else open -n -W \ --stdout "$stdout_file" \ --stderr "$stderr_file" \ --env ELECTRON_ENABLE_LOGGING=1 \ --env ORCA_STARTUP_DIAGNOSTICS=trace \ --env ORCA_STARTUP_DIAGNOSTICS_TRACE_LIMIT=30000 \ --env ORCA_STARTUP_DIAGNOSTICS_FILE="$bootstrap_file" \ "$APP_DIR" & fi local runner_pid="$!" wait_for_probe "$runner_pid" "$label" echo "ended_utc=$(date -u '+%Y-%m-%dT%H:%M:%SZ')" >>"$OUT_DIR/$label.meta" stop_log_stream "$stream_pid" } run_direct_exec_probe() { local label="direct-exec" local stderr_file="$OUT_DIR/$label.stderr.log" local stdout_file="$OUT_DIR/$label.stdout.log" local bootstrap_file="$OUT_DIR/$label.bootstrap.log" local stream_file="$OUT_DIR/$label.system-stream.log" local stream_pid diag_log "running direct exec probe" stream_pid="$(start_log_stream "$stream_file")" { echo "label=$label" echo "started_utc=$(date -u '+%Y-%m-%dT%H:%M:%SZ')" echo "bootstrap_file=$bootstrap_file" } >"$OUT_DIR/$label.meta" ELECTRON_ENABLE_LOGGING=1 \ ORCA_STARTUP_DIAGNOSTICS=trace \ ORCA_STARTUP_DIAGNOSTICS_TRACE_LIMIT=30000 \ ORCA_STARTUP_DIAGNOSTICS_FILE="$bootstrap_file" \ "$APP_DIR/Contents/MacOS/Orca" >"$stdout_file" 2>"$stderr_file" & local runner_pid="$!" wait_for_probe "$runner_pid" "$label" echo "ended_utc=$(date -u '+%Y-%m-%dT%H:%M:%SZ')" >>"$OUT_DIR/$label.meta" stop_log_stream "$stream_pid" } write_system_log_snapshot() { local predicate='process == "Orca" OR eventMessage CONTAINS[c] "Orca" OR eventMessage CONTAINS[c] "com.stablyai.orca"' if command -v log >/dev/null 2>&1; then diag_log "capturing recent unified log snapshot" command log show --style syslog --last 10m --predicate "$predicate" >"$OUT_DIR/system-log-last-10m.log" 2>&1 || true fi } package_results() { { echo "Diagnostics completed." echo "Tag: $TAG" echo "Output zip: $ZIP_PATH" echo echo "Please attach this zip to the GitHub issue:" echo " $ZIP_PATH" } >"$OUT_DIR/README.txt" diag_log "creating zip" (cd "$OUT_DIR" && zip -qry "$ZIP_PATH" .) diag_log "wrote $ZIP_PATH" } write_environment_report ensure_no_existing_orca download_and_copy_app write_app_report run_launchservices_probe "launchservices-trace" run_launchservices_probe "launchservices-bypass-lock" "ORCA_BYPASS_SINGLE_INSTANCE_LOCK" "1" run_direct_exec_probe write_system_log_snapshot package_results