fix(tui): standardize a self-animating spinner across probe surfaces (#1312)#1327
Merged
Aaronontheweb merged 2 commits intoJun 4, 2026
Merged
Conversation
…etclaw-dev#1312) Replace the five hand-rolled, drifted probe/validation spinners with Termina's existing self-animating SpinnerNode (already shipped in the 0.10.2 package), via a small shared SpinnerViews helper. This fixes the frozen ModelManager spinner, the ~1fps crawl on the provider validation/probe spinners (frame indexed on elapsed seconds), and the inconsistent cadence across surfaces. The node owns its own animation timer and propagates invalidation up the layout tree, so views just drop it in — no per-surface tick field and no hand-wired redraw subscription, which also removes the re-entrant-redraw footgun. - Add SpinnerViews with Labeled() and WithElapsed() (reactive "(Ns)" counter sibling); standardize on the Dots glyph style and 2-space indent. - Migrate SkillFeedsStepView, ProviderStepView, OAuthFlowViews, ModelManagerPage, and ProviderManagerPage onto it. - Remove the duplicated SpinnerFrames arrays, GetSpinnerFrame, the SpinnerTick reactive properties and their Invalidate subscriptions, the view-local _spinnerTick field, and the now-dead EagerProbeElapsedSeconds property + eager-probe redraw timer. - Simplify the probe timers from a 120ms fast tick to a 1Hz tick that only drives the cosmetic elapsed counter; the glyph now self-animates. No Termina change and no package bump required. Elapsed counters are preserved as reactive siblings.
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.
Closes #1312.
Problem
Probe/validation spinners in the TUI were hand-rolled per surface and had drifted, producing inconsistent — and sometimes broken — animation:
ModelManagerPage(model discovery) had no fast tick → the spinner was effectively frozen for the whole probe.ProviderStepView/ProviderManagerPageindexed the glyph onProbeElapsedSeconds(1 Hz) → the spinner crawled at ~1 fps.SkillFeedsStepViewmutated_spinnerTick++during render.SpinnerFramesarray, tick source, and redraw subscription — the root of the lazy/frozen probe spinners noted in netclaw model discover/set blocks silently while probing; 10s timeout is tight for busy self-hosted servers #1292, plus a re-entrant-redraw footgun.What this does
Termina already ships a self-animating
SpinnerNode(layout-node model) in the 0.10.2 package Netclaw already references — so this needs no Termina change and no package bump. The work is a Netclaw-side migration onto it.SpinnerViewshelper (Labeled(...)/WithElapsed(...)) that wrapsSpinnerNode, standardizing glyph style, color, and indentation. The node owns its own animation timer and propagates invalidation up the layout tree, so views just drop it in — no per-surface tick field and no hand-wired redraw subscription (which structurally removes the re-entrancy footgun).SkillFeedsStepView,ProviderStepView,OAuthFlowViews,ModelManagerPage,ProviderManagerPage.SpinnerFramesarrays (×5),GetSpinnerFrame, theSpinnerTickreactive properties + theirInvalidatesubscriptions, the view-local_spinnerTick, and the now-deadEagerProbeElapsedSecondsproperty + eager-probe redraw timer.(Ns)elapsed counter (the glyph self-animates). Elapsed counters are preserved as reactive.AsLayout()siblings.Net: +112 / −136 lines.
Validation
dotnet build(Cli + Tests): 0 warnings / 0 errorsdotnet slopwatch analyze: 0 issuesAdd-FileHeaders.ps1 -Verify: passprovider-add+provider-renametapes pass (exercise the manager validation spinner + migrated health glyphs). Theinit-wizardtape's provider-validation spinner step passes; that tape fails later on a clean-host-only assumption (the External Skills step detecting locally-installed Claude Code) unrelated to this change.