Stability fixes for the install/pairing flow - #98
Open
logikodied wants to merge 7 commits into
Open
Conversation
resource_path() shelled out to 'find' to detect an installed copy and fell back to the current working directory, which broke when althea was launched from anywhere but the repo root (and left dead code after the return). It now uses os.path against the script's real location. The AltServer/anisette-server/AltStore paths were literal "$HOME/..." strings that only worked because they were later interpolated into shell commands. They are now real paths derived from altheapath (honoring XDG_DATA_HOME), and the data directory is created with makedirs(exist_ok=True). AI-assisted written with Claude Code.
iOS versions were compared as plain strings (ios_version() >= "15.0"), which breaks for double-digit majors, and version.parse() crashed with InvalidVersion when no device was connected because ideviceinfo returned nothing and the fallback string "result" was parsed as a version. Add parse_ios_version(), which returns None in that case, and show a clear "connect and unlock your device" dialog instead of crashing. The failure dialog is dispatched to the GTK main thread via GLib.idle_add rather than being created from the worker thread. The update check in notify() gets the same numeric comparison plus a timeout and error handling. AI-assisted written with Claude Code.
AltServer was started through an f-string shell command with the Apple ID, password, and IPA path interpolated straight in, so a password containing a space, quote, or any shell metacharacter broke the command (or worse). The log redirection also used a literal $HOME path that could disagree with the XDG-aware path the monitor reads. Launch it with an argv list and env instead: no shell involved, stderr merged into the same log file the monitor reads, and the anisette server address passed via the environment. When coreutils' stdbuf is available it is used to line-buffer output so 2FA/warning prompts appear in the log promptly; when it is not, the launch still works. AI-assisted written with Claude Code.
install_process() ran a while-loop inside a GLib.idle_add callback, spawning four grep subprocesses per iteration against log.txt and never yielding, so the entire UI froze for the duration of an install and the 2FA/warning dialogs raced the loop. It also wrote prompt replies with communicate(), which closes stdin after the first reply. Rewrite it as a GLib.timeout_add(200) callback: read the log in-process via a small read_install_log() helper (which also copes with the file not existing yet), check the markers with plain substring tests, and return True/False to keep or stop the poll. Prompt replies now go through stdin.write()+flush() so the pipe stays open for a second prompt, and the warn/2FA one-shot flags live on the window instead of loop locals. AI-assisted written with Claude Code.
Three small ones found while debugging the install flow: - The splash screen probed port 6969 to see whether anisette-server was already running but then unconditionally started another instance anyway; only start one when the probe fails. - os.makedirs(.../lib/x86_64) crashed with FileExistsError on any second run that re-downloaded anisette-server; pass exist_ok=True. - command_six.set_active(command_six) passed the widget itself instead of True for the Launch at Login checkbox. AI-assisted written with Claude Code.
The AltStore feed lists two apps both named "AltStore" (the stable app and a separate beta under com.rileytestut.AltStore.Beta), and some version entries link to Patreon rather than a direct .ipa. The old code matched by name and blindly took versions[0], so it could pick the wrong app or a non-.ipa URL depending on feed ordering, and had no timeouts or error handling. - Match feed entries by bundleIdentifier instead of name. - Skip version entries whose downloadURL isn't a direct .ipa. - Add network timeouts and error handling around the feed and IPA download, and use os.replace for an atomic swap into place. AI-assisted written with Claude Code.
Cover resource_path() outside the repo tree, the XDG-derived runtime paths, read_install_log() with a missing and a populated log, and parse_ios_version() for the no-device and real-version cases. Also ignore __pycache__ and the local CLAUDE.md notes file. AI-assisted written with Claude Code.
logikodied
force-pushed
the
fix/install-monitoring-stability
branch
from
July 14, 2026 20:03
9fc11e9 to
76f1277
Compare
Author
|
Small update since opening this: I reworked the branch so every fix is its own commit instead of two big ones, which should make it much easier to review (or drop anything you don't want). Only actual code change on top of what was here before: the AltServer launch no longer hard-depends on coreutils' stdbuf. If stdbuf is on the system it's used to line-buffer the log output, and if it isn't, the install still works instead of failing with FileNotFoundError. Force-pushed, so the old commits got rewritten. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hey! 👋
Quick heads up before anything else: I'm not a hardcore dev, and I worked through these changes with Claude (Claude Code). I kept running into the flaky pairing/install behavior that others have mentioned too, where sometimes it works and sometimes it just doesn't. Instead of only patching my own machine I figured I'd try to clean it up properly and send it back, in hopes it makes althea more stable for future users. No shame in the AI assist, but I want to be upfront about it. Happy to change anything you don't like.
Each fix is its own commit so they're easy to review or drop individually:
One thing I could not fix and want to flag for whoever comes next: on iOS 26 the sideload itself succeeds but AltStore crashes the moment you open it. That one is not althea's fault. iOS 26 got stricter about signature validation, and the official AltServer fixed it in 1.7.4 by updating their codesigning library, but AltServer-Linux (the binary althea downloads) is still v0.0.5 from 2022 and has not gotten that fix (NyaMisty/AltServer-Linux#131). There's a fork experimenting with routing the signing through rcodesign, but no released binary with it yet, so I left that alone rather than ship something I couldn't verify. Documenting it here so the next person doesn't spend a weekend confused like I did.
Thanks for making althea 🙏