diff --git a/.agent/skills/impeccable/scripts/impeccable b/.agent/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.agent/skills/impeccable/scripts/impeccable +++ b/.agent/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.agent/skills/impeccable/scripts/impeccable.cmd b/.agent/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.agent/skills/impeccable/scripts/impeccable.cmd +++ b/.agent/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.agents/skills/impeccable/scripts/impeccable b/.agents/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.agents/skills/impeccable/scripts/impeccable +++ b/.agents/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.agents/skills/impeccable/scripts/impeccable.cmd b/.agents/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.agents/skills/impeccable/scripts/impeccable.cmd +++ b/.agents/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.claude/skills/impeccable/scripts/impeccable b/.claude/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.claude/skills/impeccable/scripts/impeccable +++ b/.claude/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.claude/skills/impeccable/scripts/impeccable.cmd b/.claude/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.claude/skills/impeccable/scripts/impeccable.cmd +++ b/.claude/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.cursor/skills/impeccable/scripts/impeccable b/.cursor/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.cursor/skills/impeccable/scripts/impeccable +++ b/.cursor/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.cursor/skills/impeccable/scripts/impeccable.cmd b/.cursor/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.cursor/skills/impeccable/scripts/impeccable.cmd +++ b/.cursor/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.dsh/skills/impeccable/scripts/impeccable b/.dsh/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.dsh/skills/impeccable/scripts/impeccable +++ b/.dsh/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.dsh/skills/impeccable/scripts/impeccable.cmd b/.dsh/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.dsh/skills/impeccable/scripts/impeccable.cmd +++ b/.dsh/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.gemini/skills/impeccable/scripts/impeccable b/.gemini/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.gemini/skills/impeccable/scripts/impeccable +++ b/.gemini/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.gemini/skills/impeccable/scripts/impeccable.cmd b/.gemini/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.gemini/skills/impeccable/scripts/impeccable.cmd +++ b/.gemini/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.github/skills/impeccable/scripts/impeccable b/.github/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.github/skills/impeccable/scripts/impeccable +++ b/.github/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.github/skills/impeccable/scripts/impeccable.cmd b/.github/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.github/skills/impeccable/scripts/impeccable.cmd +++ b/.github/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.grok/skills/impeccable/scripts/impeccable b/.grok/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.grok/skills/impeccable/scripts/impeccable +++ b/.grok/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.grok/skills/impeccable/scripts/impeccable.cmd b/.grok/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.grok/skills/impeccable/scripts/impeccable.cmd +++ b/.grok/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.hermes/skills/impeccable/scripts/impeccable b/.hermes/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.hermes/skills/impeccable/scripts/impeccable +++ b/.hermes/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.hermes/skills/impeccable/scripts/impeccable.cmd b/.hermes/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.hermes/skills/impeccable/scripts/impeccable.cmd +++ b/.hermes/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.kiro/skills/impeccable/scripts/impeccable b/.kiro/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.kiro/skills/impeccable/scripts/impeccable +++ b/.kiro/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.kiro/skills/impeccable/scripts/impeccable.cmd b/.kiro/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.kiro/skills/impeccable/scripts/impeccable.cmd +++ b/.kiro/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.opencode/skills/impeccable/scripts/impeccable b/.opencode/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.opencode/skills/impeccable/scripts/impeccable +++ b/.opencode/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.opencode/skills/impeccable/scripts/impeccable.cmd b/.opencode/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.opencode/skills/impeccable/scripts/impeccable.cmd +++ b/.opencode/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.pi/skills/impeccable/scripts/impeccable b/.pi/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.pi/skills/impeccable/scripts/impeccable +++ b/.pi/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.pi/skills/impeccable/scripts/impeccable.cmd b/.pi/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.pi/skills/impeccable/scripts/impeccable.cmd +++ b/.pi/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.qoder/skills/impeccable/scripts/impeccable b/.qoder/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.qoder/skills/impeccable/scripts/impeccable +++ b/.qoder/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.qoder/skills/impeccable/scripts/impeccable.cmd b/.qoder/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.qoder/skills/impeccable/scripts/impeccable.cmd +++ b/.qoder/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.rovodev/skills/impeccable/scripts/impeccable b/.rovodev/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.rovodev/skills/impeccable/scripts/impeccable +++ b/.rovodev/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.rovodev/skills/impeccable/scripts/impeccable.cmd b/.rovodev/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.rovodev/skills/impeccable/scripts/impeccable.cmd +++ b/.rovodev/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.trae-cn/skills/impeccable/scripts/impeccable b/.trae-cn/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.trae-cn/skills/impeccable/scripts/impeccable +++ b/.trae-cn/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.trae-cn/skills/impeccable/scripts/impeccable.cmd b/.trae-cn/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.trae-cn/skills/impeccable/scripts/impeccable.cmd +++ b/.trae-cn/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.trae/skills/impeccable/scripts/impeccable b/.trae/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.trae/skills/impeccable/scripts/impeccable +++ b/.trae/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.trae/skills/impeccable/scripts/impeccable.cmd b/.trae/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.trae/skills/impeccable/scripts/impeccable.cmd +++ b/.trae/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.veto/skills/impeccable/scripts/impeccable b/.veto/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.veto/skills/impeccable/scripts/impeccable +++ b/.veto/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.veto/skills/impeccable/scripts/impeccable.cmd b/.veto/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.veto/skills/impeccable/scripts/impeccable.cmd +++ b/.veto/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/.vibe/skills/impeccable/scripts/impeccable b/.vibe/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/.vibe/skills/impeccable/scripts/impeccable +++ b/.vibe/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/.vibe/skills/impeccable/scripts/impeccable.cmd b/.vibe/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/.vibe/skills/impeccable/scripts/impeccable.cmd +++ b/.vibe/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/cursor-plugin/skills/impeccable/scripts/impeccable b/cursor-plugin/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/cursor-plugin/skills/impeccable/scripts/impeccable +++ b/cursor-plugin/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/cursor-plugin/skills/impeccable/scripts/impeccable.cmd b/cursor-plugin/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/cursor-plugin/skills/impeccable/scripts/impeccable.cmd +++ b/cursor-plugin/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2 diff --git a/plugin/skills/impeccable/scripts/impeccable b/plugin/skills/impeccable/scripts/impeccable index a25e42302..eb60f8667 100755 --- a/plugin/skills/impeccable/scripts/impeccable +++ b/plugin/skills/impeccable/scripts/impeccable @@ -87,6 +87,11 @@ fi # Last resort: fetch this version's binary for the current platform from the # public release channel into the user cache. Needs network; sandboxes without # egress preinstall the binary on PATH instead. +setup_help() { + echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2 + echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2 + echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2 +} fetch_url() { if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null @@ -119,7 +124,18 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then [ "$os" = windows ] && asset="$asset.exe" url="$base/engine-v$version/$asset" tmp="$cache_root/bin/$version/.impeccable.part.$$" - mkdir -p "$cache_root/bin/$version" 2>/dev/null + if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi + # Check the actual staging file, not just directory existence: a cache from + # an earlier run can be readable but no longer writable inside a sandbox. + if ! (umask 077; : > "$tmp") 2>/dev/null; then + echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2 + setup_help + exit 127 + fi fetched=0 if fetch_url "$url"; then fetched=1 @@ -180,6 +196,9 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then exec "$cached" "$@" fi rm -f "$tmp" 2>/dev/null + echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2 + setup_help + exit 127 fi echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2 diff --git a/plugin/skills/impeccable/scripts/impeccable.cmd b/plugin/skills/impeccable/scripts/impeccable.cmd index 9c285c910..7ebe419bf 100644 --- a/plugin/skills/impeccable/scripts/impeccable.cmd +++ b/plugin/skills/impeccable/scripts/impeccable.cmd @@ -68,18 +68,27 @@ rem another launcher's probe: fail fast and quiet instead. if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127 if not defined version goto fail where curl.exe >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto curl_missing if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download" -if not exist "%IMPECCABLE_HOME%\bin\%version%" mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready +mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul +if errorlevel 1 goto cache_directory_failed +:cache_ready +rem Check the staging file too: an existing directory may be read-only. +rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe; +rem branch on the command's failure directly. Never treat a directory as a +rem staging file (later del cleanup would prompt to delete its contents). +if exist "%cached%.part\" goto cache_write_failed +(type nul >"%cached%.part") 2>nul || goto cache_write_failed set "asset=impeccable-windows-%arch%.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul if not errorlevel 1 goto verify -if not "%arch%"=="arm64" goto fail +if not "%arch%"=="arm64" goto download_failed set "asset=impeccable-windows-x64.exe" set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%" curl.exe -fsSL -o "%cached%.part" "%url%" >nul 2>nul -if errorlevel 1 goto fail +if errorlevel 1 goto download_failed :verify call :check_download @@ -176,6 +185,28 @@ if not errorlevel 1 set "probe_ok=1" del "%probe_tmp%" >nul 2>nul exit /b 0 +:cache_directory_failed +echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:cache_write_failed +echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2 +goto setup_failed + +:curl_missing +echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2 +goto setup_failed + +:download_failed +del "%cached%.part" >nul 2>nul +echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2 + +:setup_failed +echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2 +echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2 +echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2 +exit /b 127 + :fail del "%cached%.part" >nul 2>nul echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2