From 997edd3d396b2f13312fe540735511642c5c1278 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Mon, 29 Jun 2026 17:32:44 +0300 Subject: [PATCH] fix(install): soft-fail Cursor install so a missing asset can't kill the one-liner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cursor is auto-detected from ~/.cursor (present for nearly every developer), and cursor_install_plugin called `die` on download failure — so when the rogue-plugin-cursor.tar.gz release asset 404s (not yet published), the whole installer aborts AFTER the Claude/Codex installs, breaking the one-liner in prod. Make the Cursor path non-fatal: warn and continue (return 1 / catch) on download, extract, or manifest failure. Claude/Codex still install; Cursor is skipped with a clear "re-run once published" message. Mirrors in install.sh and install.ps1. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01RLk1XJQ1uWYSdn5Ro31JHv --- install.ps1 | 9 +++++++-- install.sh | 23 ++++++++++++++++------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/install.ps1 b/install.ps1 index 766ec16..0bb724d 100644 --- a/install.ps1 +++ b/install.ps1 @@ -259,22 +259,27 @@ if ($hasCursor) { } $tmp = Join-Path ([System.IO.Path]::GetTempPath()) ("rogue-cursor-" + [System.IO.Path]::GetRandomFileName()) New-Item -ItemType Directory -Path $tmp -Force | Out-Null + # Non-fatal: Cursor is detected from %USERPROFILE%\.cursor (present for nearly + # every developer), so a missing release asset or download error must NOT abort + # the run and break the Claude/Codex installs above. Warn and continue. try { Log "Downloading plugin $asset" $tarball = Join-Path $tmp 'p.tar.gz' Invoke-WebRequest -Uri $url -OutFile $tarball -UseBasicParsing -TimeoutSec 60 -ErrorAction Stop & tar -xzf $tarball -C $tmp - if ($LASTEXITCODE -ne 0) { Die "Could not extract the Cursor plugin tarball (is 'tar' available?)." } + if ($LASTEXITCODE -ne 0) { throw "Could not extract the Cursor plugin tarball (is 'tar' available?)." } $src = Get-ChildItem -Path $tmp -Recurse -Directory -Filter 'cursor' | Where-Object { Test-Path (Join-Path $_.FullName '.cursor-plugin\plugin.json') } | Select-Object -First 1 - if (-not $src) { Die "Cursor plugin manifest missing in download." } + if (-not $src) { throw "Cursor plugin manifest missing in download." } $dest = Join-Path $env:USERPROFILE '.cursor\plugins\local\rogue' if (Test-Path $dest) { Remove-Item -Recurse -Force $dest } New-Item -ItemType Directory -Path $dest -Force | Out-Null Copy-Item -Recurse -Force (Join-Path $src.FullName '*') $dest Ok "Plugin installed -> $dest" Warn2 'Fully quit and reopen Cursor, then run /rogue:status to verify.' + } catch { + Warn2 "Cursor plugin not installed ($($_.Exception.Message)). If the asset isn't published yet, re-run the installer once it is." } finally { Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue } diff --git a/install.sh b/install.sh index f0e20d0..e616fad 100755 --- a/install.sh +++ b/install.sh @@ -178,6 +178,11 @@ codex_install_plugin() { # The Team Marketplace (.cursor-plugin/marketplace.json) is the separate, admin- # driven managed/auto-update path; this one-liner does not touch it. CURSOR_INSTALL_DIR="$HOME/.cursor/plugins/local/${PLUGIN_NAME}" +# Returns non-zero (never `die`s) so a missing release asset or transient download +# failure can't abort the whole installer — Cursor is auto-detected from ~/.cursor, +# which is present for almost every developer, so a hard failure here would break +# the Claude/Codex installs that ran first. install_cursor() warns on a non-zero +# return and the run continues. cursor_install_plugin() { local tmp asset url src asset="rogue-plugin-cursor.tar.gz" @@ -187,21 +192,23 @@ cursor_install_plugin() { url="https://github.com/${ROGUE_PLUGIN_REPO}/releases/latest/download/${asset}" fi - tmp="$(mktemp -d)" || die "Could not create a temp dir for the Cursor download." + tmp="$(mktemp -d)" || { warn "Could not create a temp dir for the Cursor download."; return 1; } # shellcheck disable=SC2064 trap "rm -rf '$tmp'" RETURN note "Downloading plugin ${C_DIM}${asset}${C_RESET}" - curl -fsSL --max-time 60 -o "$tmp/p.tar.gz" "$url" \ - || die "Download failed from $url" + if ! curl -fsSL --max-time 60 -o "$tmp/p.tar.gz" "$url"; then + warn "Cursor plugin asset not available yet ($url) — skipping Cursor. Re-run the installer once it's published." + return 1 + fi mkdir -p "$tmp/extract" tar -xzf "$tmp/p.tar.gz" -C "$tmp/extract" \ - || die "Could not extract the Cursor plugin tarball." + || { warn "Could not extract the Cursor plugin tarball — skipping Cursor."; return 1; } # The tarball stages a top dir (rogue-plugin-cursor/) containing plugins/cursor/. src="$(find "$tmp/extract" -type d -path '*/plugins/cursor' | head -1)" [ -n "$src" ] && [ -f "$src/.cursor-plugin/plugin.json" ] \ - || die "Cursor plugin manifest missing in download." + || { warn "Cursor plugin manifest missing in download — skipping Cursor."; return 1; } mkdir -p "$(dirname "$CURSOR_INSTALL_DIR")" rm -rf "$CURSOR_INSTALL_DIR" @@ -452,8 +459,10 @@ install_cursor() { # The Cursor plugin ships dual dispatchers (sh + PowerShell) like Claude/Codex — # the matching runtime is the same shell running this installer, so no extra # prerequisite check. tar/curl (used in cursor_install_plugin) are assumed present. - cursor_install_plugin - note "Fully quit and reopen Cursor, then run ${C_DIM}/rogue:status${C_RESET} to verify." + # Non-fatal: a failed Cursor install must not abort the run (see cursor_install_plugin). + if cursor_install_plugin; then + note "Fully quit and reopen Cursor, then run ${C_DIM}/rogue:status${C_RESET} to verify." + fi } # ── CLI flags ─────────────────────────────────────────────────────────────────