Skip to content

Arrow-key TUI for the WinSenior menu#2

Merged
denfry merged 9 commits into
mainfrom
tui-menu
Jun 24, 2026
Merged

Arrow-key TUI for the WinSenior menu#2
denfry merged 9 commits into
mainfrom
tui-menu

Conversation

@denfry

@denfry denfry commented Jun 24, 2026

Copy link
Copy Markdown
Owner

What

Replaces the number-entry menu in WinSenior.ps1 with an arrow-key driven TUI for both the top-level menus and the detailed task/tweak selection screens.

  • / move a highlight bar, Enter selects, Space toggles a task/tweak, Esc goes back.
  • New dot-sourced library WinSenior.UI.ps1 holds all TUI primitives. Pure PowerShell, no module dependencies (works out of the box on PS 5.1+).
  • -Plain switch forces ASCII borders (+ - |) for terminals that can't render box-drawing glyphs.

How

The interactive loops are thin wrappers over pure functions — a key→action reducer (Resolve-MenuAction / Resolve-ChecklistAction) and a state→lines renderer (Get-MenuFrame / Get-ChecklistFrame). That pure seam is the Pester-tested surface, so the UI is unit-testable without a live console.

WinSenior.ps1 keeps all engine-invocation and selection logic unchanged (Get-SelectionParams, Invoke-Cleanup, Invoke-Optimize, Get-AppliedMap, & $engine @params). Only the presentation layer changed.

Design notes:

  • UI text stays English; box glyphs are built from code points ([char]0x250C) so the source file stays pure ASCII — zero encoding risk.
  • When input is redirected (CI / piped / non-interactive host), the menu prints a hint and exits instead of blocking on a raw key read — it never hangs.

Tests

  • New tests/WinSenior.UI.Tests.ps1 (Pester 5) exercises the reducers and renderers: highlight tracking, [x]/[ ] state, group headers, applied-suffix, plain-ASCII output, redirected-input fallback. CI runs the Pester 5 suite.
  • Verified locally by dot-sourcing every UI function (Pester 5 isn't installable in the dev sandbox) and rendering the real 57-task / 29-tweak registries; all .ps1 parse-check clean.

Out of scope

Mouse support, live-resize reflow, scrollbars, theme config, persisting selections to disk.

Spec: docs/superpowers/specs/2026-06-24-winsenior-tui-design.md
Plan: docs/superpowers/plans/2026-06-24-winsenior-tui.md

🤖 Generated with Claude Code

denfry and others added 9 commits June 24, 2026 08:07
Approach A: a new dot-sourced WinSenior.UI.ps1 library providing arrow-key
single-select (Show-Menu) and multi-select (Show-Checklist) screens, with pure
render functions for Pester testing. Presentation-layer only; engines and the
selection/dispatch logic in WinSenior.ps1 are unchanged. UI stays English; glyphs
built from code points so the source stays pure ASCII.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7 TDD tasks: UI library (theme/glyphs, single- and multi-select reducers and
renderers, key normalizer, painter, interactive loops with non-interactive
fallback), integration into WinSenior.ps1, and full verification. Pure render
functions are the Pester-tested seam.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Avoid the read-only $HOME automatic variable (renamed to $placedHome) and make
Write-Frame fully defensive so it never throws when no real console handle is
available (guards Clear-Host; always streams the lines as a last resort).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When input is redirected the arrow-key path can't run; degrade to exiting the
menu with a hint rather than a blocking ReadLine (which hangs where stdin never
signals end-of-input). Automation should call the engine scripts directly with
parameters.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the -Plain switch, dot-source WinSenior.UI.ps1 and Initialize-UiTheme, add
Get-CleanupItems/Get-OptimizeItems builders, drop the old Invoke-ToggleScreen,
and rewrite the main, cleanup, optimize and troubleshoot screens to use
Show-Menu / Show-Checklist. Engine invocation and selection logic are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@denfry denfry merged commit 31544ce into main Jun 24, 2026
1 check passed
@denfry denfry deleted the tui-menu branch June 24, 2026 05:39
denfry added a commit that referenced this pull request Jun 24, 2026
…erage (#3)

* refactor(core): extract shared engine library (WinSenior.Common.ps1)

The admin check, WhatIf probe, byte formatter, console+file logger, and the
System Restore point routine were copy-pasted into all three engines. Pull
them into one dot-sourced WinSenior.Common.ps1 so a fix lands once instead of
drifting between three copies.

- Each engine dot-sources Common and keeps a 1-line wrapper (Write-*Log,
  New-*RestorePoint), so every call site is unchanged.
- New-WinSeniorRestorePoint returns 'WhatIf'|'Created'|'Failed'; the caller
  owns its own $script:RestorePointMade flag and logs via a -LogAction block.
- WinSenior.ps1 drops its local Test-Admin and uses Test-AdminPrivileges.
- CI globs all root *.ps1 for parse + PSScriptAnalyzer instead of a hardcoded
  4-file list, so WinSenior.UI.ps1 is finally linted too.
- Add tests/WinSenior.Common.Tests.ps1 (Pester 5, mocked restore point).

Net -175 duplicated lines across the engines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: spec for unified report + scheduled-task installer (#2)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(report,schedule): unified report envelope + scheduled-task installer

Part A - unified report. All three engines' -ReportPath now write one envelope
via the new Write-WinSeniorReport helper in Common:
Tool/Version/Engine/Host/Timestamp/Mode/RestorePoint/DurationSec + engine-specific
Summary{} and Items[]. Each Write-*Report shrinks to a single call. Fixes a latent
trap: @() throws 'Argument types do not match' on the Generic.List[object] the
engines pass, so the helper casts via [object[]].

Part B - scheduled-task installer. New dot-sourced WinSenior.Schedule.ps1 with a
pure planner (Get-WinSeniorScheduleSpec) plus Install-/Remove-WinSeniorSchedule.
WinSenior.ps1 gains -InstallSchedule / -RemoveSchedule (fire-and-exit). Registers
a weekly unattended cleanup and a monthly read-only health scan under \WinSenior\,
reports to %ProgramData%\WinSenior\reports. Weekly trigger via the cmdlet; monthly
via the MSFT_TaskMonthlyTrigger CIM class (MonthOfYear is singular and required).

Tests: report round-trip + envelope assertions in Common.Tests; pure-spec coverage
in the new Schedule.Tests. Verified by dot-sourcing under pwsh 7 and PS 5.1 (all
three engines' reports + both trigger builds); live task registration is left to a
real machine. README documents both.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(coverage): expand engines to best-in-class (cleanup 63, optimize 49, repair 25)

Competitive gap audit vs CCleaner/BleachBit/Wise/Tron, O&O ShutUp10/privacy.sexy/
Win11Debloat/Sophia/WinUtil, and built-in troubleshooters. Every proposed gap was
grounded against the live registry first, so already-covered targets were not
duplicated.

Cleanup 57->63: win-caches, ps-modulecache, rdp-cache, livekernel, srum-db (stops
DPS), eventtranscript (stops DiagTrack); extended shadercache (OptixCache/NV_Cache)
and windows-old ($WinREAgent).

Optimize 29->49: modern Win11 privacy/debloat the tool was missing - Recall &
Click-to-Do, Copilot, tailored-ads, Spotlight policy, inking/typing & speech
telemetry, CEIP/Appraiser/WER, Delivery-Optimization P2P, OneDrive pre-signin,
cloud-clipboard(off); combined taskbar/Start ad-surface debloat, SCOOBE nag,
show-file-extensions(off), classic context menu(off), Teredo(off), Fast-Startup(off).
All reversible; none touch Defender RTP / Windows Update / Edge / Store.

Repair 13->25: restore-enabled, hosts-integrity, proxy/PAC hijack, firewall-state,
Defender signatures (update-only), SMBv1, critical scheduled-task health, BITS,
print spooler, Store health, plus report-only SSD wear and crash history. Scans are
locale-safe (CIM/registry/enums, Get-WinEvent in try/catch) and read-only; Get-AppxPackage
wrapped in try/catch for pwsh 7.

Tests: 'New coverage' Describe blocks added to all three suites. Verified by dot-sourcing
under pwsh 7 and Windows PowerShell 5.1 (registries build, IDs unique, every new repair
scan runs without throwing). README counts updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(release): v6.1.0 - changelog, build/sign tooling, git hygiene

- Bump version to 6.1.0 (Get-WinSeniorVersion single source + headers + README badge).
- Add CHANGELOG.md (Keep a Changelog) documenting the v6.1.0 work.
- Add tools/Build-Release.ps1 (zip + SHA256SUMS, version-driven) and
  tools/Sign-Scripts.ps1 (Authenticode signing of the root scripts).
- .gitignore the per-tool/editor configs (.codex/.cursor/.opencode/.windsurf/.zed,
  AGENTS.md) and the dist/ build output - they are machine-local, not project files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(common): fix restore-point logger capture under Pester 5

Use a function-local list + GetNewClosure instead of $script: scope: a script-scoped
variable read inside the closure resolves to $null across the closure module boundary,
which crashed the three New-WinSeniorRestorePoint tests with 'cannot call a method on a
null-valued expression'. Verified the closure mechanism locally (WhatIf path) under pwsh 7.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant