Skip to content

feat!: WinUI3 for Windows, Python for Linux - #57

Open
Stensel8 wants to merge 25 commits into
linux-pythonfrom
autofix/friendly-cray-wsyu8a
Open

Stensel8 wants to merge 25 commits into
linux-pythonfrom
autofix/friendly-cray-wsyu8a

Conversation

@Stensel8

@Stensel8 Stensel8 commented Sep 17, 2026

Copy link
Copy Markdown
Owner

Summary

Begin working on a Python equivalent for Linux. Also try to get a self contained WinUI3 build.

Type of change

Conventional Commit Types - choose one:

  • feat - #0075ca new functionality visible to the user
  • fix - #d73a4a bug fix

Breaking change?

  • Yes - I used feat!: or BREAKING CHANGE in my commit

Checklist

  • PR title follows conventional commits (e.g. fix: resolve startup crash)
  • CI is green
  • No passwords, API keys or sensitive data in the code

The CLI refused to start below build 26200 (Windows 11 25H2), which locked
out exactly the older hardware pcHealth was written for. Nothing in the CLI
needs 25H2: its real floor is PowerShell 7's own, Windows 10 1607.

Start.ps1 now reports the tier instead of exiting -- recommended (>= 26200),
supported (>= 19045), legacy (>= 14393, warns and continues), blocked below
that. app.ps1 keeps only the hard floor as a safety net so a normal launch
does not print the same advisory twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
winget ships with Windows 10 1809 and later, so on the legacy tier -- and on
LTSC images at any build -- it is absent. A missing native command throws
CommandNotFoundException under $ErrorActionPreference = 'Stop', taking the
whole menu down rather than just the tool the user picked.

Test-PcWinget reports it and points at Repair Winget; the Programs menu
checks inline so the absence renders through the existing winget-result path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
TargetPlatformMinVersion was pinned at 10.0.26100.0 while Start.ps1 already
allowed build 19045, so the launcher promised something the build did not.
Lower it to 10.0.19041.0 -- the nearest real SDK version below WinUI 3's own
22H2 floor -- and keep TargetFramework on the newest SDK.

Title bar customization is Windows 11 only, so extend into it only where
AppWindowTitleBar.IsCustomizationSupported() is true; Windows 10 keeps the
system caption. Below 19045 the launcher now points at the CLI, which runs
there, instead of only refusing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
19045 is where WinUI 3 stops rendering, so the CLI and the GUI share one
floor instead of the CLI reaching down to builds the GUI can never support.
Below it pcHealth exits; between 19045 and 26200 it runs and names the
recommended build. On Linux the kernel floor drops from 7.0 to 6.0, which
covers the LTS kernels current distros still ship.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Pure rename plus the path references that follow it: src/CLI becomes
src/Windows/CLI and src/GUI becomes src/Windows/GUI. Nothing else changes,
so the CLI still runs on Linux exactly as before.

This is the first half of separating the two stacks. It is deliberately
reversible: if the codebase stays shared instead, the move is one git mv
back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Linux gets its own stack. WinUI 3 cannot come along, and PowerShell 7 is not
installed on a Linux machine until someone installs it -- a poor first step for
a tool you reach for because something is already broken. Python 3 is on every
distro pcHealth targets, so this side is Python, with GTK4 and libadwaita for
the desktop app.

All 18 Linux tools are ported: system and hardware info, battery, logs, ping,
traceroute, network reset, audio restart, disk cleanup and trim, scan+repair,
package updates, topgrade, firmware and boot repair.

A tool emits styled lines and asks questions through a ToolContext, so the same
function runs under the terminal menu and inside the GTK window. Neither
front-end runs as root: privilege is raised per action through pkexec, because
a root process cannot reach the user's Wayland session and a root-owned toolkit
is a bad idea regardless.

assets/tools.json is the shared catalogue both stacks read, so the menus cannot
drift apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
ruff and mypy on src/Linux, plus a guard that the shared catalogue and the
Python registry list the same tools -- a mismatch would show a menu entry that
cannot run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Linux now has its own stack in src/Linux, so the PowerShell side no longer
carries a second platform. tools/linux/ and every $IsLinux branch are gone,
along with the helpers that only ever served them: Get-PcDesktopUser,
Get-PcPackageManager, Get-LinuxDistroInfo, Test-PcImageBasedSystem and
Get-PcCommandOutput.

Nothing is lost: all 18 Linux tools were ported to Python first, with the same
names and behaviour, and the originals stay in this repository's history.

Also fixes the VERSION lookup in app.ps1, which still pointed two directories
up after the move and so resolved to src/ instead of the repo root.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
A release ZIP used to be useless until the technician installed the .NET
Desktop Runtime and the Windows App SDK runtime on the machine they were
standing in front of to repair. Publishing self-contained puts both inside
the app, and the MSI wraps that into one file to hand someone.

WiX v6 authoring in installer/pcHealth.wxs: per-machine install, Start menu
shortcut, and a fixed UpgradeCode so a new version replaces the old one.
msiexec /qn works for unattended deployment. The portable ZIP keeps its name
so the existing WinGet manifest is unaffected.

Trimming stays off: WinUI 3 resolves XAML types by reflection, so a trimmed
build fails at runtime rather than at build time. Single-file is opt-in,
because the Windows App SDK's native binaries cannot all be merged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Two findings from the first run of the installer-build job, which is what
that job exists for:

WiX only supports Windows. On Linux it prints "all behavior after this point
is undefined" and carries on, so the job moves to a Windows runner.

WiX v6 and v7 refuse to build until the Open Source Maintenance Fee EULA is
accepted (error WIX7015). Accepting a licence on the project's behalf is not
a CI default, so the toolset is pinned to v5.0.2 -- the last release under
the plain open-source licence, building the same MSI from the same authoring.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Running the file you are looking at gave an ImportError about relative
imports, which tells the user nothing about what to do instead. The GUI
entry point now detects that it has no package context, puts src/Linux on
the path and re-enters through the package.

The missing-PyGObject hint also grew an image-based variant: on Silverblue,
Bazzite, Kinoite and MicroOS the dnf line it used to print cannot work at
all, so it points at rpm-ostree or a toolbox instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
The maintainers accept the Open Source Maintenance Fee EULA, so the toolset
no longer has to stay on v5 to avoid it. Builds pass -acceptEula, and the
comment beside it records who accepted and why the fee does not apply: it is
owed by organisations above $10,000 annual revenue that use WiX to generate
revenue, and this is a FOSS project well under that line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
WIX0251: the switch takes a value rather than standing alone, and the value
is the EULA identifier -- the same wix7 that the MSBuild property uses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
The GUI looked and felt like a terminal wearing a coat, because that is what
it was: tools printed "[1] ... [2] ... [B]" and asked for a line of text, and
the GUI had no better option than a text box captioned "Choice".

Tools now declare their options instead of rendering them. ctx.choose takes a
list of Choice, and each front-end presents it its own way -- a numbered list
in the terminal, one button per option in the GUI. ctx.ask is gone; Boot
Repair's "type CONFIRM" became two explicit confirmations, which is what the
Windows tool already did.

Two bugs the screencast made obvious: categories repeated in the sidebar,
because the list started a heading on every change while the catalogue is in
menu order and interleaves them; and output from the previous tool stayed on
screen after picking another one.

The window is now laid out like the WinUI 3 app: navigation sidebar, a Tools
page of grouped cards, and one page per tool with its own title, description,
Run button and output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Health is the Linux counterpart of the WinUI 3 Health tab: sections of checks,
each with a status the front-ends colour. It reads the same hardware-db.json
the Windows app uses for CPU and GPU release years. What it checks differs
because the systems do -- no Defender or BitLocker, but CPU mitigations, the
active LSM, the firewall, failed units and boot time.

A firmware refresh printed over 300 lines of "Downloading...: 41.4%", because
fwupd redraws one progress line with carriage returns and a pipe turns that
into separate lines. ProgressFilter keeps one per second plus the last, so the
four lines that said something are no longer buried.

Output colours were read from the theme once at construction, so switching
light/dark mid-session left them wrong; the tags repaint on notify::dark now.

smart.py is extracted so Hardware Information and Health read SMART through
one module rather than each parsing smartctl's JSON their own way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
@Stensel8 Stensel8 self-assigned this Sep 17, 2026
Copilot AI lite review requested due to automatic review settings September 17, 2026 22:18
@github-actions github-actions Bot added type/docs Documentation changes. windows-11 Windows 11 / GUI related. powershell PowerShell script changes. csharp C# source code changes. security Security-related changes or vulnerabilities. linux Linux CLI related. ci dependencies labels Sep 17, 2026
@github-actions github-actions Bot added breaking-change Introduces a breaking change. type/feature New feature or functionality. labels Sep 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

One or more issues must be addressed before approval.

Pull request overview

Introduces separate Windows WinUI 3 and Linux Python implementations, reorganizing platform-specific tooling and adding a self-contained Windows build path.

Changes:

  • Adds WinUI 3 pages, view models, services, and installer packaging.
  • Adds the Linux Python CLI/GTK foundation and tool implementations.
  • Moves Windows CLI scripts and updates paths, workflows, and documentation.
File summaries
File Description
src/Windows/GUI/Start.ps1 Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/WingetRepairViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/WindowsUpdateViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/TracerouteViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/SystemUpdateViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/SettingsViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/ScanRepairViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/PowerOptionsViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/OpenBatteryReportViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/NiniteViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/NetworkResetViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/NetworkPingViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/NetworkContinuousViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/LicenseKeyViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/InfoViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/HPUpdateViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/HealthModels.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/DiskOptimizationViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/DiskCleanupViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/CBSLogViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/BootRepairViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/BIOSPasswordViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/ViewModels/AudioRestartViewModel.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/UpdateChecker.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/ProcessRunner.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/IUpdateChecker.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/IProcessRunner.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/ICliRunner.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/IAppSettings.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/CliRunner.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Services/AppSettings.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/pcHealth.csproj Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/WingetRepairPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/WingetRepairPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/WindowsUpdatePage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/WindowsUpdatePage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/TraceroutePage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/TraceroutePage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/ToolsPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/ToolsPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/SystemUpdatePage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/SystemUpdatePage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/SystemInfoPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/SettingsPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/ScanRepairPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/ScanRepairPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/ProgramsPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/ProgramsPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/PowerOptionsPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/OpenBatteryReportPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/OpenBatteryReportPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NinitePage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NinitePage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NetworkResetPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NetworkResetPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NetworkPingPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NetworkPingPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NetworkContinuousPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/NetworkContinuousPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/InfoPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/InfoPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/HPUpdatePage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/HPUpdatePage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/HardwareInfoPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/DiskOptimizationPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/DiskOptimizationPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/DiskCleanupPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/DiskCleanupPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/CBSLogPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/CBSLogPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/BootRepairPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/BootRepairPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/BIOSPasswordPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/BIOSPasswordPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/BatteryReportPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/AudioRestartPage.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Pages/AudioRestartPage.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/NLog.config Updated as part of this pull request.
src/Windows/GUI/pcHealth/Models/ToolItem.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Models/ProgramItem.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Models/ItemGroup.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Models/InfoRow.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/MainWindow.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/MainWindow.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/Helpers/UiHelper.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Helpers/DialogHelper.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/GlobalUsings.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/Assets/pcHealth.svg Updated as part of this pull request.
src/Windows/GUI/pcHealth/App.xaml.cs Updated as part of this pull request.
src/Windows/GUI/pcHealth/App.xaml Updated as part of this pull request.
src/Windows/GUI/pcHealth/app.manifest Updated as part of this pull request.
src/Windows/GUI/.gitkeep Updated as part of this pull request.
src/Windows/CLI/tools/Test-Traceroute.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Test-NetworkShort.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Test-NetworkContinuous.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Open-CBSLog.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Open-BIOSPasswordTool.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Open-BatteryReport.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-WingetRepair.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-WindowsUpdate.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-SystemUpdate.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-PowerOptions.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-NetworkReset.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-HPUpdate.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-DiskOptimize.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-DiskCleanup.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-BootRepair.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Invoke-AudioRestart.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Get-SystemInfo.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Get-Ninite.ps1 Updated as part of this pull request.
src/Windows/CLI/tools/Get-BatteryReport.ps1 Updated as part of this pull request.
src/Windows/CLI/menus/Main.ps1 Updated as part of this pull request.
src/Windows/CLI/app.ps1 Updated as part of this pull request.
src/Linux/pyproject.toml Updated as part of this pull request.
src/Linux/pchealth/version.py Updated as part of this pull request.
src/Linux/pchealth/tools/power.py Updated as part of this pull request.
src/Linux/pchealth/tools/network.py Updated as part of this pull request.
src/Linux/pchealth/tools/logs.py Updated as part of this pull request.
src/Linux/pchealth/tools/audio.py Updated as part of this pull request.
src/Linux/pchealth/tools/init.py Updated as part of this pull request.
src/Linux/pchealth/gui/dialogs.py Updated as part of this pull request.
src/Linux/pchealth/gui/init.py Updated as part of this pull request.
src/Linux/pchealth/cli/theme.py Updated as part of this pull request.
src/Linux/pchealth/cli/init.py Updated as part of this pull request.
src/Linux/pchealth/catalog.py Updated as part of this pull request.
src/Linux/pchealth/main.py Updated as part of this pull request.
src/Linux/pchealth/init.py Updated as part of this pull request.
src/CLI/tools/Test-Traceroute.ps1 Updated as part of this pull request.
src/CLI/tools/linux/Invoke-Topgrade.ps1 Updated as part of this pull request.
src/CLI/tools/linux/Invoke-SystemUpdate.ps1 Updated as part of this pull request.
src/CLI/tools/linux/Invoke-ScanAndRepair.ps1 Updated as part of this pull request.
src/CLI/tools/linux/Invoke-NetworkReset.ps1 Updated as part of this pull request.
src/CLI/tools/linux/Invoke-DiskOptimize.ps1 Updated as part of this pull request.
src/CLI/tools/linux/Invoke-AudioRestart.ps1 Updated as part of this pull request.
src/CLI/tools/linux/Get-SystemLogs.ps1 Updated as part of this pull request.
src/CLI/tools/Invoke-PowerOptions.ps1 Updated as part of this pull request.
src/CLI/app.ps1 Updated as part of this pull request.
SECURITY.md Updated as part of this pull request.
pcHealth.sln Updated as part of this pull request.
installer/pcHealth.wxs Updated as part of this pull request.
development/tools/Invoke-ScriptAnalyzer.ps1 Updated as part of this pull request.
development/tools/Invoke-DotnetCheck.ps1 Updated as part of this pull request.
development/tools/Invoke-BomFix.ps1 Updated as part of this pull request.
.gitignore Updated as part of this pull request.
.github/workflows/security.yml Updated as part of this pull request.
.github/workflows/release.yml Updated as part of this pull request.
.github/workflows/codeql.yml Updated as part of this pull request.
.github/labeler.yml Updated as part of this pull request.
Review details

Suppressed comments (3)

src/Linux/pchealth/tools/init.py:38

  • The catalogue exposes topgrade as a selectable Linux tool, but this registry has no "topgrade" entry. Selecting it therefore always reaches implementation is None in cli/menu.py and reports that no implementation is registered, so the newly advertised tool is unusable. Add the "topgrade": updates.topgrade mapping (and keep the catalogue/registry invariant intact).
    src/Linux/pchealth/tools/audio.py:35
  • This helper always invokes sudo, even when the application is running as root or the machine only has pkexec (the documented elevation fallback). On minimal Linux installations without sudo, audio restart and other user-session actions fail despite the shared privilege helper supporting pkexec. Route this through the same available-elevation strategy or handle the root case directly.
    src/Linux/pchealth/tools/network.py:77
  • A failed network-manager restart is rendered as a successful reset: command_output receives no failed message here, and execution always reaches Network reset complete.. Propagate the non-zero return (or return early) so users are not told the reset succeeded when the service restart failed.
  • Files reviewed: 79/204 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Every run_root call spawned its own pkexec, and pkexec authenticates per
invocation. Disk Cleanup ran six privileged commands, so it asked six times.
Hardware Information asked once per disk. The Health page asked for nearly
every section it filled in.

privileged.py is elevated once and runs the whole batch, streaming each line
back as it arrives. It holds no logic and takes no decisions: it runs exactly
the argv lists handed to it on stdin as JSON, no shell involved, and exits
when the batch is done, so no root process sits waiting on a pipe. Boot
Repair passes stop_on_error so grub-mkconfig cannot run after grub-install
failed.

The Health report also stopped elevating for the firewall state. A report
that asks for the root password to tell you whether ufw is running is not
worth the interruption; it reports that the state needs root instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
@github-actions github-actions Bot removed the type/feature New feature or functionality. label Sep 18, 2026
A GUI that prints "[>>] Doing something..." into a monospace pane is a
terminal wearing a window, which is what both front-ends had become. The
cause was the contract: ctx.line(text, style) leaves a front-end nothing to
render but text.

Tools now describe results. section() is a heading, fields() a label/value
block, note() one message, and run()/run_all() a step with its raw output
attached. The terminal prints that as text; the GTK window builds groups,
rows and an expander whose command output stays folded away, because nobody
opened a GUI to read a console.

ui.run() also absorbs the six lines every tool repeated around each command
-- label, stream with an indent, check the exit code, print OK or the failure
-- and run_all() keeps the single elevation prompt.

On the Windows side, ICliRunner.RunScript was dead code and RunWinget opened
a real pwsh window that waited for a keypress. Both are gone: installing a
program reports progress on its own card now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Seven pages opened onto a wall of monospace log text with the actual result
-- a status line and a progress ring -- squeezed above it. The log now sits
behind a Details expander, so the page leads with what happened and the
output is there when you want it.

The card border inside the expander went too: the expander already draws one,
so it was a frame inside a frame with the margin applied twice.

CBS Log and Windows License Key keep their text. On those pages the text is
the result, not a byproduct.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
CliRunner still starts processes for OpenUri/OpenApp; removing RunScript
and RunWinget took the using with it and broke the build.

The four files I touched also picked up a UTF-8 BOM, which .editorconfig
(charset = utf-8) and the other 69 C# files do not have, so dotnet format
rewrote them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
…output

Both stacks asked a command-line tool for facts the platform already exposes
through an API, then parsed its prose back into values. That is a process per
answer, a dependency per answer, and output that shifts with the locale and
the tool's version.

Windows:
- Optional features come from Win32_OptionalFeature over CIM, the same
  servicing stack DISM talks to. It was six dism.exe processes, six 15-second
  timeouts and a regex over "State : Enabled".
- The audio services are driven through ServiceController. The state is an
  enum now instead of the word RUNNING somewhere in sc.exe output, and
  WaitForStatus replaces the fixed one-second guess between stop and start.

Linux: a new probe module reads /proc, /sys and the standard library, so
lscpu, uptime, findmnt, lsblk, mokutil and timedatectl are no longer needed
for the health report or the hardware and system pages. Three separate copies
of the /proc/meminfo parser and two of the lspci regex collapse into one.
desktop_user() uses pwd instead of three calls to id and getent, and open_url
uses webbrowser, which also works where xdg-open is not installed.

What has no native path keeps its tool, and says why in a comment: PCI device
names live in hwdata's pci.ids (lspci), SMART needs an ioctl (smartctl), and
unit state belongs to systemd (systemctl). GPU detection now falls back to
/sys/class/drm, so an adapter is still reported without pciutils.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
The Programs, Update All and HP Driver pages ran winget.exe and read its
console output. That output is a progress bar redrawing itself through a
pipe and prose that changes with the locale, so the app filtered it with a
"is this line a sentence" heuristic and still had no percentage to show.

The COM API answers with objects: a stage, a download fraction, an install
fraction and a typed result. The two update pages now show a real progress
bar and no log at all, and a program card says "Downloading 47%" instead of
whatever winget last managed to print.

Activation is the awkward part, and worth writing down. pcHealth runs
unpackaged, self-contained and elevated, which is exactly the combination
WinGet's manual-activation shim crashes in (microsoft/winget-cli#4377), and
the shipped projection keeps its I* interfaces internal so their IIDs cannot
be named from here. So the objects come straight from the out-of-process
CLSIDs via CoCreateInstance, asked for IInspectable and marshalled by
CsWinRT, with CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION -- undocumented in the
API reference, but WinGet's own LocalServerInstanceInitializer sets it for
this same reason: an elevated client reaching a server that is not.

Because that path can fail on a machine whose App Installer is too old or
absent, winget.exe stays as a fallback behind the same interface, chosen
once per session and never per call. UniGetUI, the largest consumer of this
API, keeps a CLI fallback for the same reason. Properties that only exist on
later revisions of the COM interfaces are set defensively, since the support
floor is Windows 10 22H2.

winget repair keeps using PowerShell: the COM server is the thing it fixes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Two findings from the Copilot review that were suppressed rather than
posted, so they never appeared as review threads. The third, a missing
topgrade entry in the tool registry, is already fixed and the catalogue
guard in CI proves it.

run_as_user always went through sudo. The GUI already runs as the desktop
user -- it must never run as root -- so restarting audio asked for a
password to run `systemctl --user`, which needs no privilege at all. That is
the same interruption the batched-elevation work was meant to remove. It now
runs the command directly when we already are that user, passing the session
bus through the process environment instead of an env(1) wrapper, and only
switches user when the process really is root. A machine with polkit but no
sudo now has a route too, instead of failing outright.

Network reset reported "Network reset complete." whatever happened, because
run_all's results were dropped on the floor. A failed NetworkManager restart
now says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Adds a Repair Windows page that opens Settings on the Recovery page, presses
"Fix problems using Windows Update" and then shows Windows Update, where the
repair build downloads. The whole repair now starts in pcHealth.

There is no API for this. It is not an update the Windows Update Agent can
install, not a CSP, not a usoclient verb: it is a Settings button that asks the
Update Session Orchestrator for a repair build of the running version. UI
Automation, the accessibility API meant for invoking UI, is the only supported
way to press it from another process, so that is what this uses.

Depending on another app's layout is the risk, so it fails safely rather than
cleverly. The button is matched on an exact label from a known list and never
on a substring, because the same page also carries "Reset PC" and a loose match
there would wipe the machine. The literal text found is put in front of the
user for confirmation before anything is pressed, and the dialog defaults to
Cancel so leaning on Enter cannot start a reinstall. When nothing matches, the
page is left open with instructions instead of guessing, and every button found
is written to the log, so an unknown build or display language is diagnosed
from one run rather than guessed at.

Not verified on hardware: this container has no Windows, so CI proves only that
it compiles. The log line "Recovery page button: id=... name=..." is what shows
whether the match worked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxhvVJmPAgyVJ8QJSp5N5X
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Introduces a breaking change. ci csharp C# source code changes. dependencies linux Linux CLI related. powershell PowerShell script changes. security Security-related changes or vulnerabilities. type/docs Documentation changes. windows-11 Windows 11 / GUI related.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants