fix: dark-mode input surfaces and stall-based install timeouts - #83
Merged
yujiezhang-ops merged 2 commits intoAug 7, 2026
Merged
Conversation
The API Key field stayed white in dark mode. Two independent causes: `.secure-field` and `.search-field` draw their own border, focus ring and background and hold the <input> as a bare text surface. The rule that themes every other field, `.field-stack > input`, is a child selector, so the wrapper in between stops it from applying. Nothing else coloured these inputs, leaving the UA sheet's white default inside a dark box. `color-scheme` also stayed at the `:root` default of `light dark`, so it followed the desktop rather than the forced palette. That controls the parts of a control the stylesheet cannot reach -- a password field's masking dots, the caret, the autofill background -- so forcing dark on a light desktop produced a dark field with a light caret, and the row still read as white. Both wrappers now carry themed colour and background with the input inheriting them, and both `.theme-dark` and `.theme-light` set `color-scheme`. Verified against computed styles in all three theme states. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Installs and runtime downloads failed on slow links. The limits were elapsed time -- 180s per command, 10min per download -- which punishes a slow transfer for being slow while doing nothing about one that has genuinely died. An app store does not give up on a slow download, it gives up on a stopped one. Both limits are now stall-based: a command that produces no output, or a transfer that receives no bytes, for the stall window is killed, while anything still making progress runs as long as it needs. The old deadlines stay as backstops at an hour, and `http.Client.Timeout` is dropped in favour of dial and response-header timeouts, since that field bounds body reads too and was itself killing healthy transfers. Stalls surface as `ErrStalled`, distinct from `context.DeadlineExceeded` and `context.Canceled`, so a dead network reads differently from the Task Center's stop button. The captured stdout and stderr go back with it: whatever the command said before going quiet is the only clue to where it stuck. Liveness is recorded before `boundedBuffer` can discard, or a command that passed its 1 MB output cap would be read as stalled while still healthy. The watchdog polls a timestamp instead of arming a timer per read, which for a 50 MB download is hundreds of thousands of reads. The frontend now sends `timeout: 0` to mean "use the Go default" instead of repeating 180, which had made it a second source of truth that disagreed silently once Go's default moved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
yujiezhang-ops
deleted the
fix/dark-mode-input-and-install-stall-timeout
branch
August 7, 2026 09:52
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.
Two independent bug fixes, one commit each.
Dark-mode text inputs (
e5fa71a)The API Key field stayed white in dark mode. Two causes, both needed fixing:
.secure-fieldand.search-fielddraw their own border, focus ring and background and hold the<input>as a bare text surface. The rule that themes every other field,.field-stack > input, is a child selector, so the wrapper in between stops it applying. Nothing else coloured these inputs, so the UA sheet's white default showed inside a dark box.color-schemealso stayed at the:rootdefault oflight dark, following the desktop rather than the forced palette. It controls the parts of a control CSS cannot reach — a password field's masking dots, the caret, the autofill background — so forcing dark on a light desktop gave a dark field with a light caret.Stall-based install timeouts (
5f84f1a)Installs and runtime downloads failed on slow links. The limits were elapsed time (180s per command, 10 min per download), which punishes a slow transfer for being slow while doing nothing about one that has actually died.
Both are now stall-based: no output from a command, or no bytes on a transfer, for the stall window ends it; anything still making progress runs as long as it needs. Old deadlines remain as one-hour backstops.
http.Client.Timeoutis replaced by dial and response-header timeouts, since that field bounds body reads too and was itself killing healthy transfers.Stalls surface as
ErrStalled, distinct fromcontext.DeadlineExceededandcontext.Canceled, so a dead network reads differently from the Task Center's stop button — and the captured stdout/stderr goes back with the error, since what the command said before going quiet is the only clue to where it stuck.Two subtleties worth a reviewer's eye: liveness is recorded before
boundedBuffercan discard, or a command past its 1 MB output cap would look stalled while healthy; and the watchdog polls a timestamp rather than arming a timer per read, which for a 50 MB download is hundreds of thousands of reads.The frontend now sends
timeout: 0to mean "use the Go default" instead of repeating180, which had been a second source of truth that disagreed silently once Go's default moved.Testing
go test ./...— all packages passgo test -race ./internal/{process,install,binding,desktopapp}— cleango vet ./...— cleanpnpm run test— 30 files / 226 tests passpnpm run build(includestsc --noEmit) — passNew coverage:
frontend/src/styles/input-surface.test.tsguards both wrappers and thecolor-schemepairing; the Go side adds stall, cancellation-vs-stall, slow-but-alive, output-flood, and output-preserved-on-stall cases.Dark mode was verified against computed styles in all three theme states (forced dark, forced light, follow-system) rather than by screenshot, since colour is what's under test.
🤖 Generated with Claude Code