fix: voice broken on user machines + Usage view scroll clipping#44
Merged
Conversation
CI-built bundles were arriving on user machines with a stackvox script
shebang pointing at /Users/runner/work/.../python3 — the CI runner's
filesystem path that pip stamped at install time. Direct execution
failed immediately with "bad interpreter, no such file or directory",
which surfaced in Settings as "Voices unavailable" and made the voice
daemon plist exit with code 78 in a KeepAlive loop.
Fix: never invoke the stackvox script directly. Always go through
`python3 <stackvox-script-path>`. python3 is a real Mach-O binary
(symlinked to python3.12) which is relocatable; calling it bypasses
the script's shebang entirely. Python finds the venv via its own
binary location, so site-packages auto-resolves.
Three call sites updated:
- Speaker.speak (daemon auto-start + say invocation)
- PanelNav.runStackvoxVoices (Settings UI voice-list query)
- Bootstrap.writeDaemonPlistIfVenvPresent (launchd plist's
ProgramArguments)
Speaker.downloadVoiceModel already invoked `python3 -u -c "..."` so
that path was unaffected — which is why model downloads worked while
voice synthesis didn't.
Existing v1.7.1 installs need to either auto-update past this commit or
manually re-run the bootstrap wizard so the daemon plist gets rewritten
with the python3-prefixed args.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Usage tab's ScrollView wasn't getting an explicit max-height claim,
so when the four quota tiers exceeded the panel's available space the
content rendered past the bottom edge and clipped behind the PageFooter
— with no visible scrollbar to hint at the overflow.
- .frame(maxHeight: .infinity) forces the scrollview to bound itself
to the available area rather than expanding to fit content.
- .scrollIndicators(.visible) overrides macOS's "auto-hide when not
scrolling" default so users see the affordance immediately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Two unrelated fixes that together justify a v1.7.2 patch:
1. Voice was unusable on every CI-built install (release blocker)
The pip-installed `stackvox` script ships with an absolute shebang stamped at install time. On the GitHub Actions runner that shebang points at `/Users/runner/work/.../python3` — a path that doesn't exist on user machines. Any direct invocation of `stackvox` fails with "bad interpreter".
User-visible symptoms:
Fix: in three call sites (`Speaker.speak`, `PanelNav.runStackvoxVoices`, `Bootstrap.writeDaemonPlistIfVenvPresent`) invoke `python3 ` instead of running the script directly. `python3` is a real Mach-O binary that's relocatable, so it works regardless of the build-time shebang. The downloadVoiceModel path already used `python3 -u -c "..."` so it was unaffected — which is exactly why model downloads worked while voice didn't.
2. Usage tab clipping
When all four quota tiers (session / weekly / Opus / Sonnet) are present, the ScrollView's content extends past the panel area and clips behind the PageFooter with no visible scrollbar hint. `.frame(maxHeight: .infinity)` + `.scrollIndicators(.visible)` fixes both.
Test plan
Migration for existing v1.7.1 users
Their daemon plist was written with the broken `[stackvox, "serve"]` ProgramArguments. After auto-updating to v1.7.2, `Bootstrap.writeDaemonPlistIfVenvPresent` only runs on a fresh wizard pass; the existing plist on disk won't auto-rewrite. Options:
🤖 Generated with Claude Code