Problem
When gentle-ai is installed via Scoop on Windows, the TUI upgrade flow always shows:
gentle-ai (skipped)
upgrade "gentle-ai" on Windows requires manual update: irm https://raw.githubusercontent.com/Gentleman-Programming/...
This forces users to manually run scoop update gentle-ai instead of pressing Enter in the TUI.
Root Cause
Two files need changes:
1. internal/update/instructions.go
The gentleAIHint function always returns irm ... for Windows without detecting Scoop:
func gentleAIHint(profile system.PlatformProfile) string {
switch profile.OS {
case "windows":
return "irm https://...install.ps1 | iex" // Always irm, no Scoop detection
}
}
Fix: Add Scoop detection:
func gentleAIHint(profile system.PlatformProfile) string {
switch profile.OS {
case "windows":
if isScoopInstall() {
return "scoop update gentle-ai"
}
return "irm https://...install.ps1 | iex"
}
}
func isScoopInstall() bool {
exe, err := os.Executable()
if err != nil {
return false
}
resolved, err := filepath.EvalSymlinks(exe)
if err != nil {
return false
}
return strings.Contains(strings.ToLower(resolved), filepath.Join("scoop", "apps", "gentle-ai"))
}
2. internal/update/upgrade/strategy.go
The binaryUpgrade function returns ManualFallbackError on Windows for all binary tools:
func binaryUpgrade(ctx context.Context, r update.UpdateResult, profile system.PlatformProfile) error {
if profile.OS == "windows" {
return &ManualFallbackError{
Hint: fmt.Sprintf("upgrade %q on Windows requires manual update: %s", r.Tool.Name, hint),
}
}
}
Fix: Add Scoop upgrade strategy before the manual fallback:
func binaryUpgrade(ctx context.Context, r update.UpdateResult, profile system.PlatformProfile) error {
if r.Tool.Name == "engram" {
return engramBinaryUpgrade(profile)
}
if profile.OS == "windows" {
if isScoopInstall() {
return scoopUpgrade(ctx, r.Tool.Name)
}
return &ManualFallbackError{...}
}
return downloadAndReplace(ctx, r, profile)
}
func scoopUpgrade(ctx context.Context, toolName string) error {
cmd := execCommand("scoop", "update", toolName)
cmd.Stdin = nil
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("scoop update %s: %w (output: %s)", toolName, err, string(out))
}
return nil
}
3. internal/update/types.go (optional)
Add InstallScoop constant for explicit method tracking:
const (
InstallBrew InstallMethod = "brew"
InstallScoop InstallMethod = "scoop" // NEW
InstallBinary InstallMethod = "binary"
// ...
)
Expected Behavior
When installed via Scoop on Windows:
- TUI shows
scoop update gentle-ai as the update command
- Pressing Enter auto-upgrades via
scoop update gentle-ai (no manual intervention)
- Falls back to
irm only when NOT installed via Scoop
Detection Logic
Scoop installs to ~/scoop/apps/gentle-ai/current/ with symlinks. Detect by checking if the resolved executable path contains scoop/apps/gentle-ai.
Environment
- OS: Windows
- Install method: Scoop (
scoop bucket add gentleman ... && scoop install gentle-ai)
- Version: 1.28.3 -> 1.29.1
Problem
When
gentle-aiis installed via Scoop on Windows, the TUI upgrade flow always shows:This forces users to manually run
scoop update gentle-aiinstead of pressing Enter in the TUI.Root Cause
Two files need changes:
1.
internal/update/instructions.goThe
gentleAIHintfunction always returnsirm ...for Windows without detecting Scoop:Fix: Add Scoop detection:
2.
internal/update/upgrade/strategy.goThe
binaryUpgradefunction returnsManualFallbackErroron Windows for all binary tools:Fix: Add Scoop upgrade strategy before the manual fallback:
3.
internal/update/types.go(optional)Add
InstallScoopconstant for explicit method tracking:Expected Behavior
When installed via Scoop on Windows:
scoop update gentle-aias the update commandscoop update gentle-ai(no manual intervention)irmonly when NOT installed via ScoopDetection Logic
Scoop installs to
~/scoop/apps/gentle-ai/current/with symlinks. Detect by checking if the resolved executable path containsscoop/apps/gentle-ai.Environment
scoop bucket add gentleman ... && scoop install gentle-ai)