fix(updater): SEA-aware install detection — recognise bin/claude.exe
After upstream switched to SEA (Single Executable Application) layout in v2.1.114+, there is no cli.js anymore — only bin/claude.exe. Before this fix: - find_cli_js() searched only for cli.js → returned None on SEA installs - get_installed_version() returned (None, None) → "Claude Code: not installed" - is_patched() returned (False, [3 markers]) → false-negative even after successful patch - cmd_check showed "not installed" right after a successful update - cmd_update would loop reinstalling because patch markers seemed missing This contributed to a user-facing incident where /model picker showed only built-in models even though CLAUDE_CUSTOM_MODELS was set in settings.json: the binary update path was triggering uninstall+reinstall cycles instead of being recognised as already-patched. Changes: - New find_claude_artifact() finds either cli.js or bin/claude.exe, including the deeply-nested layout npm uses for SEA wrapper packages - find_all_cli_js() returns both legacy and SEA artifacts - is_patched() auto-detects layout: text scan for cli.js, bytes scan for claude.exe (markers: /*ae1_models_filter_patched*/, /*bypass_permissions_prompt*/) - get_installed_version() reads package.json next to bin/ for SEA - uclaude_install.sh adds binary marker verification at end of install so users immediately see if the SEA payload was patched Tests: new tests/test_sea_detect.py covers all 4 detector functions against fake SEA install layouts (including nested form). All 20 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -193,6 +193,40 @@ else
|
||||
echo " (no $SETTINGS to verify — patcher may not have run)"
|
||||
fi
|
||||
|
||||
# Verify the installed binary itself carries patcher markers — catches the
|
||||
# case where patcher.config.json + settings.json are correct but the binary
|
||||
# wasn't actually patched (e.g. npm overwrote it after install).
|
||||
echo ""
|
||||
echo " Binary patch verification:"
|
||||
CLAUDE_BIN="$(readlink -f "$(command -v claude 2>/dev/null)" 2>/dev/null || true)"
|
||||
if [ -n "$CLAUDE_BIN" ] && [ -f "$CLAUDE_BIN" ]; then
|
||||
case "$(basename "$CLAUDE_BIN")" in
|
||||
cli.js)
|
||||
if grep -q '__CLAUDE_SETTINGS__\|/\*bypass_permissions_prompt\*/' "$CLAUDE_BIN" 2>/dev/null; then
|
||||
echo " cli.js: OK (patcher markers present)"
|
||||
else
|
||||
echo " cli.js: ⚠ NOT patched ($CLAUDE_BIN — re-run uclaude_updater.py --force)"
|
||||
fi
|
||||
;;
|
||||
claude.exe|claude)
|
||||
# SEA binary — grep -a treats binary as text
|
||||
sea_ok=true
|
||||
grep -aq '/\*ae1_models_filter_patched' "$CLAUDE_BIN" 2>/dev/null || sea_ok=false
|
||||
grep -aq '/\*bypass_permissions_prompt' "$CLAUDE_BIN" 2>/dev/null || sea_ok=false
|
||||
if $sea_ok; then
|
||||
echo " SEA binary: OK (ae1_models_filter + bypass_permissions markers)"
|
||||
else
|
||||
echo " SEA binary: ⚠ NOT fully patched ($CLAUDE_BIN — re-run uclaude_updater.py --force)"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo " (unknown artifact: $CLAUDE_BIN)"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo " (no claude binary on PATH — check installation)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " Run claude: claude # interactive"
|
||||
echo " Update later: cd $INSTALL_DIR && sudo bash claude/uclaude_update.sh"
|
||||
|
||||
Reference in New Issue
Block a user