fix: gzip decompression, infinite retry loops, and keychain hangs#16
Open
davidfencik wants to merge 6 commits intosteipete:mainfrom
Open
fix: gzip decompression, infinite retry loops, and keychain hangs#16davidfencik wants to merge 6 commits intosteipete:mainfrom
davidfencik wants to merge 6 commits intosteipete:mainfrom
Conversation
Go's http.Transport handles gzip decompression transparently when Accept-Encoding is not set manually. Setting it explicitly disables automatic decompression, causing raw gzip bytes to reach json.Decoder and producing 'invalid character' errors on most endpoints. Fixes steipete#14
The do() method recursed indefinitely on 429 (rate limit) and 401 (unauthorized) responses. This could hang the CLI forever when the API consistently returns these status codes. Add a retry counter (max 3) with exponential backoff for 429s.
The macOS Keychain backend blocks indefinitely in headless environments (SSH, cron, launchd) when it cannot show the authorization prompt. Detect headless mode via SSH_TTY or missing TERM and fall back to file-only backend. Interactive terminal users keep Keychain as default. Can also be forced with EIGHTCTL_KEYRING_FILE=1. Fixes steipete#10
563dcf4 to
92e8e81
Compare
added 3 commits
February 20, 2026 12:32
Corrects field mappings for sleep data parsing: - sleepDuration (not sleepDurationSeconds) - Adds deepDuration, remDuration, lightDuration, sleepStart/End - Properly nests sleepQualityScore with hrv, heartRate, respiratoryRate - Fixes sleep range --from/--to flag parsing (read from cobra, not viper) - Displays durations in hours for readability Inspired by talison's analysis in steipete#11.
…uality) Adds to sleep day/range output: - quality (sleepQualityScore.total) - awake_min (presenceDuration - sleepDuration) - disturbances (renamed from tnt) - avg_rhr (rolling average resting heart rate) - lowest_hr (min from session timeseries heartRate data) - breath_rate (respiratoryRate.current) - snore_min (snoreDuration in minutes) Parses sessions[].timeseries.heartRate array to extract lowest HR. Also adds presenceDuration, snoreDuration, heavySnoreDuration to SleepDay struct.
- Add --side flag to sleep day/range: left, right, partner, or me - Fix --date flag reading from cobra instead of viper (same fix as --from/--to) - Fix OAuth token endpoint using hardcoded 'sleep-client' instead of actual client ID - Add GetSleepDayForUser() to query any user's trends - Add Device().SideUserIDs() and UserIDForSide() helpers
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.
Summary
Three fixes that resolve CLI hangs and endpoint failures, especially on macOS in headless environments.
Fixes: #10, #14 (and the root cause behind most symptoms in #12)
Changes
1. Remove explicit
Accept-Encoding: gzipheadersGo's
http.Transporthandles gzip transparently whenAccept-Encodingis not set manually. Setting it explicitly disables automatic decompression, causing raw gzip bytes to reachjson.Decoder→invalid character '\\x1f'errors on most endpoints.2. Add max retries for 429/401 responses
do()recursed infinitely on 429 (rate limit) and 401 (unauthorized). Added a retry cap (3) with linear backoff to prevent the CLI from hanging forever.3. Skip macOS Keychain in headless environments
The macOS Keychain backend blocks indefinitely in headless environments (SSH, cron, launchd) waiting for an auth prompt that can never be shown. Now detects headless mode (
SSH_TTYset,TERMmissing) and falls back to file backend. Interactive users keep Keychain as default. Can also be forced withEIGHTCTL_KEYRING_FILE=1.Testing
go test ./...)status,sleep day,whoami,device infoall work on macOS (Apple Silicon, headless via launchd)Context
I was setting up eightctl to run as part of a home automation system (via launchd on macOS). Hit all three issues in sequence: gzip errors, infinite retry loops, and keychain hangs. Debugged with the help of an AI coding assistant (Claude/OpenClaw) by reading the source, tracing the issues, and building locally.
Each fix is a separate commit for easy review.