From 7193f4020c29147e8e2fc3a7a066ae6ca66d1eb7 Mon Sep 17 00:00:00 2001 From: Bruno <281018252+bruno-archastro@users.noreply.github.com> Date: Fri, 30 Oct 2026 17:41:30 +0000 Subject: [PATCH 1/3] Probe healthy skill bootstraps only once --- archdev/scripts/bootstrap.ps1 | 15 ++++++++---- archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../codex/skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../grok/skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../grok/skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- .../pi/skills/archdev/scripts/bootstrap.ps1 | 15 ++++++++---- .../pi/skills/archdev/scripts/bootstrap.sh | 24 ++++++++++++------- scripts/fake-archdev | 3 +++ scripts/test-skill-bootstrap.ps1 | 11 ++++++++- scripts/test-skill-bootstrap.sh | 7 +++++- 21 files changed, 253 insertions(+), 119 deletions(-) diff --git a/archdev/scripts/bootstrap.ps1 b/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/archdev/scripts/bootstrap.ps1 +++ b/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/archdev/scripts/bootstrap.sh b/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/archdev/scripts/bootstrap.sh +++ b/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 b/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/antigravity/skills/archdev/scripts/bootstrap.sh b/plugins/antigravity/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/antigravity/skills/archdev/scripts/bootstrap.sh +++ b/plugins/antigravity/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/claude/skills/archdev/scripts/bootstrap.ps1 b/plugins/claude/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/claude/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/claude/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/claude/skills/archdev/scripts/bootstrap.sh b/plugins/claude/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/claude/skills/archdev/scripts/bootstrap.sh +++ b/plugins/claude/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/codex/skills/archdev/scripts/bootstrap.ps1 b/plugins/codex/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/codex/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/codex/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/codex/skills/archdev/scripts/bootstrap.sh b/plugins/codex/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/codex/skills/archdev/scripts/bootstrap.sh +++ b/plugins/codex/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 b/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/copilot/skills/archdev/scripts/bootstrap.sh b/plugins/copilot/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/copilot/skills/archdev/scripts/bootstrap.sh +++ b/plugins/copilot/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 b/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/cursor/skills/archdev/scripts/bootstrap.sh b/plugins/cursor/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/cursor/skills/archdev/scripts/bootstrap.sh +++ b/plugins/cursor/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/grok/skills/archdev/scripts/bootstrap.ps1 b/plugins/grok/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/grok/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/grok/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/grok/skills/archdev/scripts/bootstrap.sh b/plugins/grok/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/grok/skills/archdev/scripts/bootstrap.sh +++ b/plugins/grok/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 b/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/opencode/skills/archdev/scripts/bootstrap.sh b/plugins/opencode/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/opencode/skills/archdev/scripts/bootstrap.sh +++ b/plugins/opencode/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/plugins/pi/skills/archdev/scripts/bootstrap.ps1 b/plugins/pi/skills/archdev/scripts/bootstrap.ps1 index cc380b6..17e506d 100644 --- a/plugins/pi/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/pi/skills/archdev/scripts/bootstrap.ps1 @@ -34,6 +34,7 @@ $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + if ($LASTEXITCODE -ne 0) { return $false } try { return ([Version]$raw -ge $minVersion) } catch { @@ -145,6 +146,8 @@ function Update-HomebrewArchDev([string]$Binary) { } } +# Cache success only for this invocation, never across an install/repair. +$skillChecked = $false $existing = Get-Command archdev -ErrorAction SilentlyContinue $candidate = if ($existing) { Resolve-ArchDevPath $existing.Source } else { $null } $homebrewArchDev = Find-HomebrewArchDev $candidate @@ -153,12 +156,16 @@ if ($homebrewArchDev) { if ($candidate -and $candidate -ne $archdev) { [Console]::Error.WriteLine("Using Homebrew-managed ArchDev at $archdev; $candidate comes first on PATH.") } - if (-not (Test-LinkedFile $archdev) -or -not (Test-Skill $archdev)) { + if ((Test-LinkedFile $archdev) -and (Test-Skill $archdev)) { + $skillChecked = $true + } else { Update-HomebrewArchDev $archdev } } else { $archdev = if ($candidate) { $candidate } else { Install-ArchDev } - if (-not (Test-Skill $archdev)) { + if (Test-Skill $archdev) { + $skillChecked = $true + } else { [Console]::Error.WriteLine("Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.") $archdev = Install-ArchDev } @@ -170,9 +177,7 @@ if ($homebrewArchDev -and -not (Test-LinkedFile $archdev)) { if (-not (Test-Path -LiteralPath $archdev -PathType Leaf)) { throw "ArchDev installer did not create an executable at $archdev" } -& $archdev --version *> $null -if ($LASTEXITCODE -ne 0) { throw "ArchDev version verification failed" } -if (-not (Test-Skill $archdev)) { +if (-not $skillChecked -and -not (Test-Skill $archdev)) { if ($homebrewArchDev) { throw "Homebrew-managed ArchDev at $archdev still fails the capability check after brew; not installing a second copy." } throw "Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback" } diff --git a/plugins/pi/skills/archdev/scripts/bootstrap.sh b/plugins/pi/skills/archdev/scripts/bootstrap.sh index 297ba3d..c45c555 100755 --- a/plugins/pi/skills/archdev/scripts/bootstrap.sh +++ b/plugins/pi/skills/archdev/scripts/bootstrap.sh @@ -60,9 +60,9 @@ install_archdev() ( ) version_ok() { - local raw version - raw="$("$1" --version 2>/dev/null | head -n 1)" - version="$(printf '%s' "$raw" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" + local version + checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] } @@ -155,6 +155,10 @@ update_homebrew_archdev() { fi } +# Reuse successful checks only within this invocation. Installing or repairing +# the binary leaves this false so the replacement is checked from scratch. +skill_checked=false +checked_version="" candidate="$(command -v archdev 2>/dev/null || true)" homebrew_archdev="$(find_homebrew_archdev "$candidate" || true)" if [[ -n "$homebrew_archdev" ]]; then @@ -162,7 +166,9 @@ if [[ -n "$homebrew_archdev" ]]; then if [[ -n "$candidate" && "$(absolute_path "$candidate")" != "$executable" ]]; then printf 'Using Homebrew-managed ArchDev at %s; %s comes first on PATH.\n' "$executable" "$(absolute_path "$candidate")" >&2 fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else update_homebrew_archdev "$executable" || exit 1 fi else @@ -172,7 +178,9 @@ else install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" fi - if ! supports_skill "$executable"; then + if supports_skill "$executable"; then + skill_checked=true + else printf 'Updating ArchDev: this skill requires 0.49.6+ and repository hook setup with --local.\n' >&2 install_archdev || exit 1 executable="$(absolute_path "$install_dir/archdev")" @@ -188,14 +196,14 @@ fi exit 1 } -"$executable" --version >&2 -supports_skill "$executable" || { +if [[ "$skill_checked" != true ]] && ! supports_skill "$executable"; then if [[ -n "$homebrew_archdev" ]]; then printf 'Homebrew-managed ArchDev at %s still fails the capability check after brew; not installing a second copy.\n' "$executable" >&2 fi printf 'Installed ArchDev lacks required commands or --local hook setup (need 0.49.6+); stopping without a global fallback.\n' >&2 exit 1 -} +fi +printf '%s\n' "$checked_version" >&2 # Resolving the executable must not choose configuration scope. Install and # repair hooks only through the approved branch in https://archdev.ai/install.md. diff --git a/scripts/fake-archdev b/scripts/fake-archdev index 47ee839..d9ba80f 100755 --- a/scripts/fake-archdev +++ b/scripts/fake-archdev @@ -10,6 +10,9 @@ set -euo pipefail args="$*" +if [[ -n "${ARCHDEV_FAKE_INVOCATIONS:-}" ]]; then + printf '%s\n' "$args" >>"$ARCHDEV_FAKE_INVOCATIONS" +fi case "$args" in --version) echo "${ARCHDEV_FAKE_VERSION:-0.49.6}" ;; "tasks review update --help") echo "Usage: archdev tasks review update [options] " ;; diff --git a/scripts/test-skill-bootstrap.ps1 b/scripts/test-skill-bootstrap.ps1 index 57ce037..57e7854 100644 --- a/scripts/test-skill-bootstrap.ps1 +++ b/scripts/test-skill-bootstrap.ps1 @@ -16,7 +16,7 @@ $onWindows = $env:OS -eq "Windows_NT" $caseVariables = @( "CLAUDECODE", "CODEX_THREAD_ID", "GROK_SESSION_ID", "USERPROFILE", "ARCHDEV_FACTORY_AGENT_ROLE", "ARCHDEV_JOB_ID", "ARCHDEV_STEP_ID", - "ARCHDEV_FAKE_SETUP_EXIT", "ARCHDEV_FAKE_LOG", "ARCHDEV_FAKE_NO_LOCAL", "ARCHDEV_FAKE_NO_HEARTBEAT", "ARCHDEV_FAKE_NO_INBOX", "ARCHDEV_FAKE_VERBOSE_HELP", "ARCHDEV_FAKE_VERSION", "ARCHDEV_INSTALL_DIR" + "ARCHDEV_FAKE_SETUP_EXIT", "ARCHDEV_FAKE_LOG", "ARCHDEV_FAKE_INVOCATIONS", "ARCHDEV_FAKE_NO_LOCAL", "ARCHDEV_FAKE_NO_HEARTBEAT", "ARCHDEV_FAKE_NO_INBOX", "ARCHDEV_FAKE_VERBOSE_HELP", "ARCHDEV_FAKE_VERSION", "ARCHDEV_INSTALL_DIR" ) $savedPath = $env:PATH $savedHome = $env:HOME @@ -57,6 +57,7 @@ function Invoke-Case { if ($onWindows) { $env:USERPROFILE = $homeDir } $env:PATH = $casePath $env:ARCHDEV_FAKE_LOG = $log + $env:ARCHDEV_FAKE_INVOCATIONS = Join-Path $caseDir "invocations.log" # Linux PowerShell has no LOCALAPPDATA; rejection tests must reach the # intercepted download, not fail while constructing a Windows default. $env:ARCHDEV_INSTALL_DIR = Join-Path $caseDir "install" @@ -102,6 +103,14 @@ exit 0 $script:failures++ return } + if ($Skill -eq "archdev") { + $calls = @(Get-Content -LiteralPath (Join-Path $caseDir "invocations.log")) + if ($calls.Count -ne 7 -or @($calls | Select-Object -Unique).Count -ne 7) { + Write-Host "FAIL ${Name}: healthy core bootstrap must probe version and six capabilities once" + $script:failures++ + return + } + } $actual = (Get-Content -LiteralPath $log -Raw) $actual = if ($actual) { $actual.Trim() } else { "" } if ($actual -eq $Expected) { diff --git a/scripts/test-skill-bootstrap.sh b/scripts/test-skill-bootstrap.sh index ad68300..817d904 100755 --- a/scripts/test-skill-bootstrap.sh +++ b/scripts/test-skill-bootstrap.sh @@ -20,7 +20,7 @@ run_bootstrap() { chmod +x "$case_dir/bin/archdev" "$case_dir/bin/curl" : >"$case_dir/setup.log" if ! out="$(env -i HOME="$case_dir/home" PATH="$case_dir/bin:/usr/bin:/bin" \ - ARCHDEV_FAKE_LOG="$case_dir/setup.log" "$@" \ + ARCHDEV_FAKE_LOG="$case_dir/setup.log" ARCHDEV_FAKE_INVOCATIONS="$case_dir/invocations.log" "$@" \ bash "$repo/$skill/scripts/bootstrap.sh" 2>"$case_dir/stderr")"; then printf 'FAIL %s: bootstrap exited nonzero\n' "$name" >&2 cat "$case_dir/stderr" >&2 @@ -32,6 +32,11 @@ run_bootstrap() { failures=$((failures + 1)) return fi + if [[ "$skill" == archdev ]] && [[ "$(wc -l <"$case_dir/invocations.log" | tr -d ' ')" != 7 || "$(sort "$case_dir/invocations.log" | uniq -d)" != "" ]]; then + printf 'FAIL %s: healthy core bootstrap must probe version and six capabilities once\n' "$name" >&2 + failures=$((failures + 1)) + return + fi printf 'ok %s: executable resolved, no hook installation or refresh\n' "$name" } From 87bcafb7cc88d49441342a3d9f0b7fdd8f5ae9cd Mon Sep 17 00:00:00 2001 From: Bruno <281018252+bruno-archastro@users.noreply.github.com> Date: Fri, 30 Oct 2026 18:00:37 +0000 Subject: [PATCH 2/3] Drain version output before checking native exit status --- archdev/scripts/bootstrap.ps1 | 5 ++++- archdev/scripts/bootstrap.sh | 5 +++-- plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/antigravity/skills/archdev/scripts/bootstrap.sh | 5 +++-- plugins/claude/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/claude/skills/archdev/scripts/bootstrap.sh | 5 +++-- plugins/codex/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/codex/skills/archdev/scripts/bootstrap.sh | 5 +++-- plugins/copilot/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/copilot/skills/archdev/scripts/bootstrap.sh | 5 +++-- plugins/cursor/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/cursor/skills/archdev/scripts/bootstrap.sh | 5 +++-- plugins/grok/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/grok/skills/archdev/scripts/bootstrap.sh | 5 +++-- plugins/opencode/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/opencode/skills/archdev/scripts/bootstrap.sh | 5 +++-- plugins/pi/skills/archdev/scripts/bootstrap.ps1 | 5 ++++- plugins/pi/skills/archdev/scripts/bootstrap.sh | 5 +++-- scripts/fake-archdev | 9 ++++++++- scripts/test-skill-bootstrap.ps1 | 3 ++- scripts/test-skill-bootstrap.sh | 3 +++ 21 files changed, 76 insertions(+), 29 deletions(-) diff --git a/archdev/scripts/bootstrap.ps1 b/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/archdev/scripts/bootstrap.ps1 +++ b/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/archdev/scripts/bootstrap.sh b/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/archdev/scripts/bootstrap.sh +++ b/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 b/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/antigravity/skills/archdev/scripts/bootstrap.sh b/plugins/antigravity/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/antigravity/skills/archdev/scripts/bootstrap.sh +++ b/plugins/antigravity/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/claude/skills/archdev/scripts/bootstrap.ps1 b/plugins/claude/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/claude/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/claude/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/claude/skills/archdev/scripts/bootstrap.sh b/plugins/claude/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/claude/skills/archdev/scripts/bootstrap.sh +++ b/plugins/claude/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/codex/skills/archdev/scripts/bootstrap.ps1 b/plugins/codex/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/codex/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/codex/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/codex/skills/archdev/scripts/bootstrap.sh b/plugins/codex/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/codex/skills/archdev/scripts/bootstrap.sh +++ b/plugins/codex/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 b/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/copilot/skills/archdev/scripts/bootstrap.sh b/plugins/copilot/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/copilot/skills/archdev/scripts/bootstrap.sh +++ b/plugins/copilot/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 b/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/cursor/skills/archdev/scripts/bootstrap.sh b/plugins/cursor/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/cursor/skills/archdev/scripts/bootstrap.sh +++ b/plugins/cursor/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/grok/skills/archdev/scripts/bootstrap.ps1 b/plugins/grok/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/grok/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/grok/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/grok/skills/archdev/scripts/bootstrap.sh b/plugins/grok/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/grok/skills/archdev/scripts/bootstrap.sh +++ b/plugins/grok/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 b/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/opencode/skills/archdev/scripts/bootstrap.sh b/plugins/opencode/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/opencode/skills/archdev/scripts/bootstrap.sh +++ b/plugins/opencode/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/plugins/pi/skills/archdev/scripts/bootstrap.ps1 b/plugins/pi/skills/archdev/scripts/bootstrap.ps1 index 17e506d..8d85463 100644 --- a/plugins/pi/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/pi/skills/archdev/scripts/bootstrap.ps1 @@ -33,8 +33,11 @@ function Install-ArchDev { $minVersion = [Version]"0.49.6" function Test-Version([string]$Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" + # Drain native output before selecting a line. Select-Object -First 1 in + # the native pipeline may stop the process and manufacture a nonzero exit. + $versionLines = @(& $Binary --version 2>$null) if ($LASTEXITCODE -ne 0) { return $false } + $raw = ($versionLines | Select-Object -First 1) -replace "[^0-9.]", "" try { return ([Version]$raw -ge $minVersion) } catch { diff --git a/plugins/pi/skills/archdev/scripts/bootstrap.sh b/plugins/pi/skills/archdev/scripts/bootstrap.sh index c45c555..870ab3f 100755 --- a/plugins/pi/skills/archdev/scripts/bootstrap.sh +++ b/plugins/pi/skills/archdev/scripts/bootstrap.sh @@ -60,8 +60,9 @@ install_archdev() ( ) version_ok() { - local version - checked_version="$("$1" --version 2>/dev/null | head -n 1)" || return 1 + local raw version + raw="$("$1" --version 2>/dev/null)" || return 1 + checked_version="${raw%%$'\n'*}" version="$(printf '%s' "$checked_version" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)" [[ -n "$version" ]] || return 1 [[ "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" == "$min_version" ]] diff --git a/scripts/fake-archdev b/scripts/fake-archdev index d9ba80f..e12364a 100755 --- a/scripts/fake-archdev +++ b/scripts/fake-archdev @@ -14,7 +14,14 @@ if [[ -n "${ARCHDEV_FAKE_INVOCATIONS:-}" ]]; then printf '%s\n' "$args" >>"$ARCHDEV_FAKE_INVOCATIONS" fi case "$args" in - --version) echo "${ARCHDEV_FAKE_VERSION:-0.49.6}" ;; + --version) + echo "${ARCHDEV_FAKE_VERSION:-0.49.6}" + if [[ "${ARCHDEV_FAKE_VERBOSE_VERSION:-0}" == 1 ]]; then + for ((line = 0; line < 4096; line++)); do + printf 'Additional version diagnostic output\n' + done + fi + ;; "tasks review update --help") echo "Usage: archdev tasks review update [options] " ;; "tasks heartbeat --help") [[ "${ARCHDEV_FAKE_NO_HEARTBEAT:-0}" == 1 ]] && exit 1 diff --git a/scripts/test-skill-bootstrap.ps1 b/scripts/test-skill-bootstrap.ps1 index 57e7854..84edd6e 100644 --- a/scripts/test-skill-bootstrap.ps1 +++ b/scripts/test-skill-bootstrap.ps1 @@ -16,7 +16,7 @@ $onWindows = $env:OS -eq "Windows_NT" $caseVariables = @( "CLAUDECODE", "CODEX_THREAD_ID", "GROK_SESSION_ID", "USERPROFILE", "ARCHDEV_FACTORY_AGENT_ROLE", "ARCHDEV_JOB_ID", "ARCHDEV_STEP_ID", - "ARCHDEV_FAKE_SETUP_EXIT", "ARCHDEV_FAKE_LOG", "ARCHDEV_FAKE_INVOCATIONS", "ARCHDEV_FAKE_NO_LOCAL", "ARCHDEV_FAKE_NO_HEARTBEAT", "ARCHDEV_FAKE_NO_INBOX", "ARCHDEV_FAKE_VERBOSE_HELP", "ARCHDEV_FAKE_VERSION", "ARCHDEV_INSTALL_DIR" + "ARCHDEV_FAKE_SETUP_EXIT", "ARCHDEV_FAKE_LOG", "ARCHDEV_FAKE_INVOCATIONS", "ARCHDEV_FAKE_NO_LOCAL", "ARCHDEV_FAKE_NO_HEARTBEAT", "ARCHDEV_FAKE_NO_INBOX", "ARCHDEV_FAKE_VERBOSE_HELP", "ARCHDEV_FAKE_VERBOSE_VERSION", "ARCHDEV_FAKE_VERSION", "ARCHDEV_INSTALL_DIR" ) $savedPath = $env:PATH $savedHome = $env:HOME @@ -307,6 +307,7 @@ try { Invoke-Case "$skill-no-local" "" @{ ARCHDEV_FAKE_NO_LOCAL = "1" } $skill $true Invoke-Case "$skill-old-version" "" @{ ARCHDEV_FAKE_VERSION = "0.46.0" } $skill $true } + Invoke-Case "archdev-verbose-version" "" @{ ARCHDEV_FAKE_VERBOSE_VERSION = "1" } "archdev" Invoke-Case "tasks-execute-no-heartbeat" "" @{ ARCHDEV_FAKE_NO_HEARTBEAT = "1" } "tasks-execute" $true Invoke-Case "tasks-audit-no-inbox" "" @{ ARCHDEV_FAKE_NO_INBOX = "1" } "tasks-audit" $true } finally { diff --git a/scripts/test-skill-bootstrap.sh b/scripts/test-skill-bootstrap.sh index 817d904..45f58d2 100755 --- a/scripts/test-skill-bootstrap.sh +++ b/scripts/test-skill-bootstrap.sh @@ -52,6 +52,9 @@ for skill in archdev tasks tasks-execute tasks-audit; do run_bootstrap "$skill-setup-would-fail" "$skill" CLAUDECODE=1 ARCHDEV_FAKE_SETUP_EXIT=1 done +# Version output must also be drained before checking native exit status. +run_bootstrap "archdev-verbose-version" archdev ARCHDEV_FAKE_VERBOSE_VERSION=1 + # Consume the entire help stream: with pipefail, grep -q can close early, # SIGPIPE the producer, and trigger an unnecessary install of a current CLI. for skill in archdev tasks tasks-execute tasks-audit; do From 1921bb1de501f2197a2295e2747cbcea6ed5376a Mon Sep 17 00:00:00 2001 From: Bruno <281018252+bruno-archastro@users.noreply.github.com> Date: Fri, 30 Oct 2026 19:00:15 +0000 Subject: [PATCH 3/3] Preserve Homebrew repair classification on failed verbose version probes --- archdev/scripts/bootstrap.ps1 | 9 ++++++--- archdev/scripts/bootstrap.sh | 10 +++++----- .../skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- .../antigravity/skills/archdev/scripts/bootstrap.sh | 10 +++++----- plugins/claude/skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- plugins/claude/skills/archdev/scripts/bootstrap.sh | 10 +++++----- plugins/codex/skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- plugins/codex/skills/archdev/scripts/bootstrap.sh | 10 +++++----- .../copilot/skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- plugins/copilot/skills/archdev/scripts/bootstrap.sh | 10 +++++----- plugins/cursor/skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- plugins/cursor/skills/archdev/scripts/bootstrap.sh | 10 +++++----- plugins/grok/skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- plugins/grok/skills/archdev/scripts/bootstrap.sh | 10 +++++----- .../opencode/skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- .../opencode/skills/archdev/scripts/bootstrap.sh | 10 +++++----- plugins/pi/skills/archdev/scripts/bootstrap.ps1 | 9 ++++++--- plugins/pi/skills/archdev/scripts/bootstrap.sh | 10 +++++----- scripts/test-skill-bootstrap.ps1 | 10 +++++++--- scripts/test-skill-bootstrap.sh | 13 ++++++++++++- 20 files changed, 118 insertions(+), 76 deletions(-) diff --git a/archdev/scripts/bootstrap.ps1 b/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/archdev/scripts/bootstrap.ps1 +++ b/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/archdev/scripts/bootstrap.sh b/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/archdev/scripts/bootstrap.sh +++ b/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 b/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/antigravity/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/antigravity/skills/archdev/scripts/bootstrap.sh b/plugins/antigravity/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/antigravity/skills/archdev/scripts/bootstrap.sh +++ b/plugins/antigravity/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/claude/skills/archdev/scripts/bootstrap.ps1 b/plugins/claude/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/claude/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/claude/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/claude/skills/archdev/scripts/bootstrap.sh b/plugins/claude/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/claude/skills/archdev/scripts/bootstrap.sh +++ b/plugins/claude/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/codex/skills/archdev/scripts/bootstrap.ps1 b/plugins/codex/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/codex/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/codex/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/codex/skills/archdev/scripts/bootstrap.sh b/plugins/codex/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/codex/skills/archdev/scripts/bootstrap.sh +++ b/plugins/codex/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 b/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/copilot/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/copilot/skills/archdev/scripts/bootstrap.sh b/plugins/copilot/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/copilot/skills/archdev/scripts/bootstrap.sh +++ b/plugins/copilot/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 b/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/cursor/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/cursor/skills/archdev/scripts/bootstrap.sh b/plugins/cursor/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/cursor/skills/archdev/scripts/bootstrap.sh +++ b/plugins/cursor/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/grok/skills/archdev/scripts/bootstrap.ps1 b/plugins/grok/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/grok/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/grok/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/grok/skills/archdev/scripts/bootstrap.sh b/plugins/grok/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/grok/skills/archdev/scripts/bootstrap.sh +++ b/plugins/grok/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 b/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/opencode/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/opencode/skills/archdev/scripts/bootstrap.sh b/plugins/opencode/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/opencode/skills/archdev/scripts/bootstrap.sh +++ b/plugins/opencode/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/plugins/pi/skills/archdev/scripts/bootstrap.ps1 b/plugins/pi/skills/archdev/scripts/bootstrap.ps1 index 8d85463..89bc311 100644 --- a/plugins/pi/skills/archdev/scripts/bootstrap.ps1 +++ b/plugins/pi/skills/archdev/scripts/bootstrap.ps1 @@ -136,10 +136,13 @@ function Update-HomebrewArchDev([string]$Binary) { } $version = $null if (Test-LinkedFile $Binary) { - $raw = (& $Binary --version 2>$null | Select-Object -First 1) -replace "[^0-9.]", "" - try { $version = [Version]$raw } catch { $version = $null } + $versionOutput = @(& $Binary --version 2>$null) + if ($LASTEXITCODE -eq 0) { + $raw = ($versionOutput | Select-Object -First 1) -replace "[^0-9.]", "" + try { $version = [Version]$raw } catch { $version = $null } + } } - # Only a readable, too-old version needs an upgrade; anything else is broken. + # Only a successful, too-old version needs an upgrade; anything else is broken. $action = if ($version -and $version -lt $minVersion) { "upgrade" } else { "reinstall" } [Console]::Error.WriteLine("Updating Homebrew-managed ArchDev at ${Binary}: brew $action $brewFormula") # Callers read stdout as the archdev path, so brew's progress goes to stderr. diff --git a/plugins/pi/skills/archdev/scripts/bootstrap.sh b/plugins/pi/skills/archdev/scripts/bootstrap.sh index 870ab3f..19d6b1c 100755 --- a/plugins/pi/skills/archdev/scripts/bootstrap.sh +++ b/plugins/pi/skills/archdev/scripts/bootstrap.sh @@ -133,7 +133,7 @@ find_homebrew_archdev() { # missing, crashes, or a current version fails the capability probes, where # upgrade would be a no-op. update_homebrew_archdev() { - local binary="$1" action=reinstall brew version="" + local binary="$1" action=reinstall brew raw version="" # The brew that owns this keg; another prefix's brew could install a second copy. brew="$(real_path "$binary")" brew="${brew%%/Cellar/archdev/*}/bin/brew" @@ -142,11 +142,11 @@ update_homebrew_archdev() { printf 'Not installing a second copy of ArchDev.\n' >&2 return 1 fi - if [[ -x "$binary" ]]; then - version="$("$binary" --version 2>/dev/null | head -n 1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" + if [[ -x "$binary" ]] && raw="$("$binary" --version 2>/dev/null)"; then + version="$(printf '%s' "${raw%%$'\n'*}" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)" fi - # Only a readable, too-old version needs an upgrade; anything else is broken. - if [[ -n "$version" ]] && ! version_ok "$binary"; then + # Only a successful, too-old version needs an upgrade; anything else is broken. + if [[ -n "$version" && "$(printf '%s\n%s\n' "$min_version" "$version" | sort -V | head -n 1)" != "$min_version" ]]; then action=upgrade fi printf 'Updating Homebrew-managed ArchDev at %s: brew %s %s\n' "$binary" "$action" "$brew_formula" >&2 diff --git a/scripts/test-skill-bootstrap.ps1 b/scripts/test-skill-bootstrap.ps1 index 84edd6e..85023fa 100644 --- a/scripts/test-skill-bootstrap.ps1 +++ b/scripts/test-skill-bootstrap.ps1 @@ -135,7 +135,7 @@ function Invoke-BrewCase { [string]$Skill, # An old keg is 0.49.0; every other keg is the formula's latest, 0.60.0, # so a `brew upgrade` of it changes nothing, as with real Homebrew. - [ValidateSet("old", "stub", "crash", "current", "missing", "none")][string]$Keg, + [ValidateSet("old", "stub", "crash", "version-error", "current", "missing", "none")][string]$Keg, [ValidateSet("yes", "no", "fail")][string]$Brew, [ValidateSet("none", "old", "current")][string]$Copy, # upgrade / reinstall: brew repairs the keg; current: used as is; @@ -145,7 +145,7 @@ function Invoke-BrewCase { [string]$ErrorText = "", # opt: PATH reaches the keg through Homebrew's opt link. # other-brew: another prefix's brew comes first on PATH. - [ValidateSet("", "opt", "other-brew")][string]$Variant = "" + [ValidateSet("", "opt", "other-brew", "verbose")][string]$Variant = "" ) $label = "brew $Skill-$Name" $caseDir = Join-Path $work "brew-$Skill-$Name" @@ -169,6 +169,7 @@ function Invoke-BrewCase { "stub" { Set-Content -LiteralPath $kegArchDev -Value "#!/bin/sh`necho `"archdev 3.0.0`""; & chmod +x $kegArchDev } # A binary that crashes before it can report a version. "crash" { Set-Content -LiteralPath $kegArchDev -Value "#!/bin/sh`nexit 139"; & chmod +x $kegArchDev } + "version-error" { Set-Content -LiteralPath $kegArchDev -Value "#!/bin/sh`necho 'archdev 0.60.0'`nexit 139"; & chmod +x $kegArchDev } "missing" { Remove-Item -LiteralPath (Join-Path $prefix "Cellar/archdev") -Recurse -Force } } & ln -s "../Cellar/archdev/$kegVersion/bin/archdev" (Join-Path $prefixBin "archdev") @@ -208,6 +209,7 @@ function Invoke-BrewCase { $env:FAKE_BREW_LOG = $brewLog $env:FAKE_BREW_PREFIX = $prefix $env:FAKE_BREW_EXIT = if ($Brew -eq "fail") { "1" } else { "0" } + $env:ARCHDEV_FAKE_VERBOSE_VERSION = if ($Variant -eq "verbose") { "1" } else { "0" } $env:ARCHDEV_INSTALL_DIR = Join-Path $caseDir "install" $runner = Join-Path $caseDir "runner.ps1" $bootstrap = (Join-Path $repo "$Skill/scripts/bootstrap.ps1").Replace("'", "''") @@ -226,7 +228,7 @@ exit 0 } finally { $env:PATH = $savedPath $env:HOME = $savedHome - foreach ($name in @("ARCHDEV_FAKE_BIN", "FAKE_BREW_LOG", "FAKE_BREW_PREFIX", "FAKE_BREW_EXIT")) { Remove-Item "Env:$name" -ErrorAction SilentlyContinue } + foreach ($name in @("ARCHDEV_FAKE_BIN", "FAKE_BREW_LOG", "FAKE_BREW_PREFIX", "FAKE_BREW_EXIT", "ARCHDEV_FAKE_VERBOSE_VERSION")) { Remove-Item "Env:$name" -ErrorAction SilentlyContinue } } $errorText = Get-Content (Join-Path $caseDir "stderr") -Raw if (-not $errorText) { $errorText = "" } @@ -276,6 +278,8 @@ try { Invoke-BrewCase "outdated" $skill -Keg old -Brew yes -Copy none -Expect upgrade # The incident: a stub reporting 3.0.0 passed the version check and # failed the capability probes, so `brew upgrade` would be a no-op. + Invoke-BrewCase "verbose-old" $skill -Keg old -Brew yes -Copy none -Expect upgrade -Variant verbose + Invoke-BrewCase "version-error" $skill -Keg version-error -Brew yes -Copy none -Expect reinstall Invoke-BrewCase "broken" $skill -Keg stub -Brew yes -Copy none -Expect reinstall Invoke-BrewCase "crash" $skill -Keg crash -Brew yes -Copy none -Expect reinstall Invoke-BrewCase "opt" $skill -Keg old -Brew yes -Copy none -Expect upgrade -Variant opt diff --git a/scripts/test-skill-bootstrap.sh b/scripts/test-skill-bootstrap.sh index 45f58d2..72ed1a0 100755 --- a/scripts/test-skill-bootstrap.sh +++ b/scripts/test-skill-bootstrap.sh @@ -95,7 +95,7 @@ fake_archdev_at() { chmod +x "$1" } -# brew_case +# brew_case # [] # An old keg is 0.49.0; every other keg is the formula's latest, 0.60.0, so a # `brew upgrade` of it changes nothing, as with real Homebrew. @@ -120,6 +120,7 @@ brew_case() { stub) printf '#!/bin/sh\necho "archdev 3.0.0"\n' >"$keg_dir/archdev" && chmod +x "$keg_dir/archdev" ;; # A binary that crashes before it can report a version. crash) printf '#!/bin/sh\nexit 139\n' >"$keg_dir/archdev" && chmod +x "$keg_dir/archdev" ;; + version-error) printf '#!/bin/sh\necho "archdev 0.60.0"\nexit 139\n' >"$keg_dir/archdev" && chmod +x "$keg_dir/archdev" ;; missing) rm -rf "$prefix/Cellar/archdev" ;; esac ln -s "../Cellar/archdev/$keg_version/bin/archdev" "$prefix/bin/archdev" @@ -154,6 +155,7 @@ brew_case() { ARCHDEV_FAKE_LOG="$case_dir/setup.log" ARCHDEV_FAKE_BIN="$repo/scripts/fake-archdev" \ FAKE_BREW_LOG="$case_dir/brew.log" FAKE_BREW_PREFIX="$prefix" \ FAKE_BREW_EXIT="$([[ "$brew" == fail ]] && echo 1 || echo 0)" \ + ARCHDEV_FAKE_VERBOSE_VERSION="$([[ "$variant" == verbose ]] && echo 1 || echo 0)" \ bash "$repo/$skill/scripts/bootstrap.sh" >"$case_dir/out" 2>"$case_dir/stderr" case_exit=$? set -e @@ -216,6 +218,15 @@ for skill in archdev tasks tasks-execute tasks-audit; do # The incident: a stub reporting 3.0.0 passed the version check and failed # the capability probes, so `brew upgrade` would have been a no-op. + brew_case verbose-old "$skill" old yes none verbose + if expect_brew_repaired upgrade && expect_no_second_copy; then + printf 'ok %s: verbose outdated Homebrew version upgraded\n' "$skill" + fi + brew_case version-error "$skill" version-error yes none + if expect_brew_repaired reinstall && expect_no_second_copy; then + printf 'ok %s: failed version command reinstalled despite version text\n' "$skill" + fi + brew_case broken "$skill" stub yes none expect_brew_repaired reinstall && expect_no_second_copy && printf 'ok %s: broken current Homebrew copy reinstalled with brew, no second copy\n' "$skill"