207 Commits

Author SHA1 Message Date
dfae1f136b Merge pull request 'fix(build): drop invalid --no-incremental from dotnet publish' (#33) from fix/clean-publish-flag into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 9s
2026-06-10 22:26:28 +00:00
sysadmin
74e48aa1e5 fix(build): drop invalid --no-incremental from dotnet publish (MSB1001)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 8s
dotnet publish rejects --no-incremental (it's a dotnet build switch) -> MSB1001 Unknown
switch -> build failed. The bin/obj wipe alone forces the clean recompile we need.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 23:26:08 +01:00
a6ac6ce355 Merge pull request 'fix(build): clean compile before publish (CI shipped a stale toolbox DLL)' (#32) from fix/ci-clean-publish into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 31s
2026-06-10 22:21:30 +00:00
sysadmin
9832121dbb fix(build): clean compile before publish (CI shipped stale Core.dll)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 1m31s
The deployed toolbox Core.dll was timestamped BEFORE its own build ran -- the CI runner's
incremental build reused a cached SilverOS.Welcome.Core.dll, so source fixes (e.g. the winget
bootstrap brace fix) never reached the published exe. Wipe all bin/obj under welcome/ and pass
--no-incremental so every build is a clean compile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 23:21:04 +01:00
d0a5925652 Merge pull request 'fix(apps): winget bootstrap never ran (unbalanced-brace parse error) — the real apps-skip cause' (#31) from fix/winget-bootstrap-brace into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 5m32s
2026-06-10 21:44:32 +00:00
sysadmin
e91c4de7ed fix(apps): winget bootstrap never ran (unbalanced-brace parse error in inline cmd)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 36s
appinstall.log on the VM showed: bootstrap-winget exit=1 'Unexpected token }'. The
inline -Command was built from an interpolated string ($"...{{...}}" -> {/}) concatenated
with a NON-interpolated string whose '}}' stayed literal, so the emitted PowerShell ended
in '}}' and failed to parse -> the bootstrap (and thus winget install) never executed ->
all apps skipped on every run, regardless of network. Invoke the bootstrap .ps1 file
directly instead (it self-checks + installs winget online); fall back to the inbox
re-register only when the script is absent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 22:44:05 +01:00
51ab88b1f8 Merge pull request 'fix(toolbox): move Done 'Restart now' button to the footer-right (was clipped)' (#30) from fix/done-restart-footer into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 5m41s
2026-06-10 18:12:19 +00:00
sysadmin
709744d533 feat(apps): AppInstaller writes a diagnostic log (winget resolve + bootstrap + per-app)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 2s
Writes C:\ProgramData\SilverMetal\appinstall.log (best-effort) so a post-install mount
shows exactly where app installs fail: winget probe results, bootstrap-winget output,
and per-app winget exit codes. Makes the no-apps-installed failure diagnosable instead
of inferred.
2026-06-10 19:12:11 +01:00
sysadmin
ddd8784b56 fix(toolbox): move Done 'Restart now' to footer-right (was clipped in content)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 33s
The in-content Restart button overflowed its fixed width. Move it into the wizard
footer's right slot (where Next/Apply sits) as a btn-primary; Routes owns the restart
shutdown now, DoneStep just shows the recovery key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 19:06:53 +01:00
226a823c68 Merge pull request 'fix: track driver .exe (NetKVM inject) + winget online bootstrap — the two app-install blockers' (#29) from fix/driver-exe-and-winget into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 4m0s
2026-06-10 16:22:52 +00:00
sysadmin
67befa56df fix(build): track driver .exe files (gitignore *.exe dropped netkvmp.exe -> DISM rejected NetKVM)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 5m49s
The global .gitignore '*.exe' rule silently excluded netkvmp.exe + netkvmco.exe when the
NetKVM driver was committed, so only inf/sys/cat shipped. netkvm.inf REQUIRES netkvmp.exe
([SourceDisksFiles] + netkvmp.CopyFiles), so Add-WindowsDriver failed every build with 'the
driver package could not be installed' -> no virtio NIC driver -> no VM network. Un-ignore
windows/drivers/** and force-add the referenced binaries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 17:22:07 +01:00
sysadmin
13df66d137 feat(apps): bootstrap-winget downloads + installs the App Installer online (LTSC lacks it) 2026-06-10 17:21:27 +01:00
541a17c792 Merge pull request 'ci(windows): free build working set before the persist copy (persist OOM)' (#28) from ci/free-before-persist into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 6m24s
2026-06-10 15:35:35 +00:00
sysadmin
9fa613b8c1 ci(windows): free build working set before persist copy (oscdimg OK, persist OOM)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 45s
Build got through the ISO repack but failed copying the 5GB ISO to C:\silvermetal\out
('not enough space'): the build's working set (extracted ISO tree + expanded install.wim
+ 5GB base ISO) fills the single-volume runner, leaving <5GB for the persist copy. The
image grew again with the injected driver. Delete RUNNER_TEMP\smbuild + base.iso (no
longer needed post-build/validate) right before the copy to reclaim ~10GB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 16:35:01 +01:00
8f61d5fb61 Merge pull request 'fix(build): driver inject non-fatal + ForceUnsigned (NetKVM rejected, bricked build)' (#27) from fix/driver-inject-resilient into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 7m24s
2026-06-10 13:41:42 +00:00
sysadmin
09e1f94b7d fix(build): driver inject non-fatal + ForceUnsigned + .gitattributes binary
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 7m35s
Add-WindowsDriver rejected the virtio NetKVM driver during offline servicing and
aborted the whole build. A driver issue must not brick the image: wrap it in try/catch
(warn + continue) and add -ForceUnsigned to bypass the offline-inject signature check
(the driver is WHQL-signed and loads at boot regardless). Add .gitattributes marking
driver/binary files as binary so the runner checkout never EOL-normalizes them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 14:41:22 +01:00
8ceb38c3dd Merge pull request 'fix(collector): button footer + inject virtio NIC driver (HVCI network)' (#26) from fix/collector-button-layout into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 4m46s
2026-06-10 13:32:59 +00:00
sysadmin
a169d2a452 feat(build): inject virtio-net (NetKVM) driver for HVCI-compatible VM networking
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 4m56s
The privacy hardening enables HVCI (Memory Integrity), which blocks the legacy
e1000 NIC driver (E1G6032E.sys) -> no network in the VM, so winget app installs
silently skip. virtio-net's NetKVM driver is WHQL-signed + HVCI-compatible. Staged
from virtio-win (w11/amd64) under windows/drivers/netkvm/; build.ps1 already auto-
injects any *.inf under windows/drivers/ into install.wim. Pair with a virtio NIC on
the VM (already switched). Lets apps actually install under hardening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 14:32:48 +01:00
sysadmin
20743e9b54 fix(collector): move Finish/Cancel into a clean footer (were overlapping Confirm PIN) 2026-06-10 14:29:52 +01:00
75f97778f8 Merge pull request 'feat(toolbox): first-run lands on the Apps picker (not silent auto-apply)' (#25) from fix/first-run-apps-picker into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 6m13s
2026-06-10 13:11:42 +00:00
sysadmin
18475fa731 feat(toolbox): first-run lands on the Apps picker (not silent auto-apply)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 6m14s
Hands-on VM testing showed auto-apply skipped the app picker entirely -- the user
couldn't review/adjust apps before install. Land first-run on the Apps step instead
(pre-checked with the collector flavour's defaults); the user adjusts then walks
Apps -> Prefs -> Apply -> Done. The collector already owns account + flavour, so
Welcome/Flavour are skipped. Reverses the earlier auto-apply behavior per operator
feedback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 14:11:28 +01:00
04a6f6eabb Merge pull request 'fix(collector): carry preconfig via chunked FirstLogonCommands (specialize Path too long)' (#24) from fix/answer-file-specialize-length into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 7m34s
2026-06-10 09:35:34 +00:00
sysadmin
7e99d7e304 fix(collector): carry preconfig via chunked FirstLogonCommands (specialize Path was too long -> answer file invalid)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 5m44s
2026-06-10 10:34:47 +01:00
731ae88adf Merge pull request 'fix(collector): launch via Setup\CmdLine (collector was bypassed into Setup)' (#23) from fix/collector-launch-via-setup-cmdline into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 5m47s
2026-06-10 09:14:19 +00:00
sysadmin
fce4b77bd6 fix(collector): launch via Setup\CmdLine (was bypassed) + WinPE diagnostics
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 4m8s
The boot.wim Setup\CmdLine override (legacy-Setup forcing) is authoritative over
winpeshl.ini, so it launched setup.exe directly and the collector never ran -- the
VM went straight to the old sm-bootstrap unattended install. Repoint Setup\CmdLine
at the collector (cmd /c X:\sm\Start-Collector.cmd); the collector still launches the
legacy X:\sources\setup.exe itself. Add wpeinit + an on-screen banner, and write any
collector/WinForms-load failure to X:\sm\collector-error.txt shown on the console
before falling back, so we can diagnose WinForms-in-WinPE.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:14:08 +01:00
3538f43267 Merge pull request 'ci(windows): free disk space before build (fixes oscdimg out-of-space)' (#22) from ci/free-disk-before-build into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 24s
2026-06-10 08:50:14 +00:00
sysadmin
7eec584a66 ci(windows): free disk space before build (clear prior ISO output)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 21s
The boot.wim now carries WinPE-NetFx/PowerShell (collector), growing the image ~0.4GB,
and each build persists a ~5GB ISO to C:\silvermetal\out. On the single-volume runner
that accumulation starved oscdimg ('Insufficient disk space'). Clear prior output +
stale smbuild work dirs at job start so free space self-heals each run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:50:00 +01:00
c154e70495 Merge pull request 'feat: WinPE pre-config collector + simplified first-boot toolbox (SP1)' (#21) from docs/winpe-preconfig-collector into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 3m51s
2026-06-10 08:40:57 +00:00
sysadmin
e6c292da25 ci(windows): install ADK WinPE add-on so boot.wim collector can be staged
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 7m26s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:38:13 +01:00
sysadmin
6c96e92fa5 fix(collector): drop 'essentials' from flavour radios (it's the baseline role, not a flavour)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 5m18s
2026-06-10 09:35:59 +01:00
sysadmin
a82ca271a0 feat(build): scrub Panther unattend + assert collector baked into boot.wim
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:28:45 +01:00
bd215cba54 Merge pull request 'perf(welcome): cut first-boot cold-start + add loading affordance' (#20) from fix/welcome-cold-start into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 21s
Reviewed-on: #20
2026-06-10 08:27:18 +00:00
sysadmin
084dd6a1d7 fix(collector): pre-launch XML parse-check (fail to default) + resolve setup.exe path 2026-06-10 09:25:57 +01:00
sysadmin
9d05a4a223 feat(build): stage WinPE collector into boot.wim (winpeshl + WinPE-NetFx/PowerShell) with SM_UNATTENDED fallback
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:22:14 +01:00
sysadmin
5bc345b1bd feat(toolbox): first-run auto-applies the collected preconfig (no manual walkthrough) 2026-06-10 09:19:11 +01:00
sysadmin
e88e476cd6 feat(toolbox): drop Account step, pre-seed from preconfig, run-once vs toolbox-home
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:12:39 +01:00
sysadmin
2730b29cb6 refactor(toolbox): drop unused IProcessRunner from ApplyService ctor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 09:08:14 +01:00
sysadmin
30a168e853 perf(welcome): cut first-boot cold-start + add loading affordance
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m46s
The Welcome wizard showed nothing until WebView2 cold-started and Blazor
booted, so the whole startup cost presented as a blank window long enough
that operators thought first boot had failed.

- Native MAUI splash overlay (renders in the first frame, no WebView2/JIT
  dependency) + a visually identical in-page splash inside #app, so the
  native -> webview -> Blazor handoff reads as one continuous loading
  screen. Fades out on first successful WV2 NavigationCompleted.
- PublishReadyToRun=true (publish-only) to remove first-run JIT on the
  one-shot cold-disk path. R2R header verified present after publish.
- Fixed-version WebView2 runtime baked offline next to the exe (build.ps1
  stages it, app points WEBVIEW2_BROWSER_EXECUTABLE_FOLDER at it). Removes
  the Evergreen registry probe and the LTSC "no WebView2 at all" risk flagged
  in welcome-app-spec.md; air-gap friendly. Absent => falls back to Evergreen.
- De-flash launch: drop the `cmd /c` wrapper and add -WindowStyle Hidden in
  autounattend FirstLogonCommands (kills the console flash + one process).

Verified: Release build clean, win-x64 self-contained publish succeeds with
R2R confirmed, 38/38 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:06:02 +01:00
sysadmin
f3d66fb9d3 refactor(toolbox): Apply is apps+bitlocker only (account via Setup, hardening via SetupComplete)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:04:09 +01:00
sysadmin
bd1e2885df feat(toolbox): preconfig store (load fail-open, clear-pin, configured marker)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 08:56:32 +01:00
sysadmin
42d86734b0 feat(collector): answer-file generator (real account, no sm-bootstrap, embedded preconfig) 2026-06-10 08:51:35 +01:00
sysadmin
72e401113a feat(collector): WinPE input validation helpers + Pester tests 2026-06-10 08:45:58 +01:00
sysadmin
27a08ac1ab docs(welcome): WinPE pre-config collector implementation plan (SP1)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 08:37:15 +01:00
sysadmin
59418e37c8 docs(welcome): WinPE pre-config collector design spec (SP1)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 08:30:48 +01:00
72fa329ddd Merge pull request 'fix(apps): winget launch failure no longer crashes Apply' (#19) from fix/winget-launch-resilience into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 6m30s
2026-06-10 00:24:02 +00:00
sysadmin
3daa770584 fix(apps): winget launch failure no longer crashes Apply
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 4m44s
On IoT LTSC winget is absent, so Process.Start('winget') throws Win32Exception
('cannot find the file specified') rather than returning non-zero. That throw
propagated out of InstallAsync and failed the entire Apply ('Configuration failed').

AppInstaller is now fully exception-safe: a TryRunAsync wrapper converts launch
throws into a failed run, winget is resolved defensively (PATH -> bootstrap+re-probe
-> WindowsApps alias path) and when unavailable the installer skips apps and marks
them not-installed instead of throwing. Per-app launch throws are isolated too.
Two new tests cover probe-throws-skips and per-app-throw-isolated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 01:23:49 +01:00
f6dac0fdfd Merge pull request 'fix(ci): ISO-assert discards stale WIM mount (was blocking ISO persist)' (#18) from fix/iso-assert-stale-mount into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 5m45s
2026-06-10 00:02:42 +00:00
sysadmin
4268a337f3 fix(ci): ISO-assert discards stale WIM mount + asserts app catalog baked
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 5m55s
Assert-IsoStructure.ps1 reused a fixed mount dir; a prior aborted run left a WIM
mounted there, so Mount-WindowsImage failed with 'directory is not empty' and the
persist-to-stable-path step was skipped (no ISO deployed). Now discards stale mounts
+ clears corrupt mount points + uses a unique per-run mount dir (mirrors build.ps1
Stage 0), and removes the dir after. Also asserts apps/catalog.json baked into the WIM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 01:02:31 +01:00
129b8741fd Merge pull request 'feat(welcome): per-role app recipes in the first-boot wizard' (#17) from feat/app-recipes into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 5m27s
2026-06-09 23:54:29 +00:00
sysadmin
260023a1a5 feat(apps): catalog.json + chromium configure + winget bootstrap + build staging
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 6m36s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:41:18 +01:00