When `webPassword` is null and the daemon starts headless (systemd, piped
SSH), no longer auto-generate a random password. Instead:
- Boot normally with the gate denying everything except /api/auth/setup
- Panel UI eagerly probes new /api/auth/state on load and renders a
first-run setup overlay (password + confirm) when needsSetup=true
- POST /api/auth/setup writes the chosen password and issues the auth
cookie in the same response, so the operator lands logged in
Interactive TTY behaviour (prompt at the console) is unchanged. The gate
middleware is now registered unconditionally so first-run mode is still
locked-down instead of wide-open.
Adds three structural assertions that run after the zip is built:
1. No backslash separators in any entry name. NeoForge needs
"META-INF/neoforge.mods.toml" to be at exactly that forward-slash
path; PowerShell 5.1's [ZipFile]::CreateFromDirectory() puts
"META-INF\neoforge.mods.toml" instead, which the loader silently
rejects. The current build code uses CreateEntry with explicit
forward slashes, but this guard fires if anyone reverts to the
simpler-looking CreateFromDirectory.
2. META-INF/neoforge.mods.toml exists at the canonical path. Without
it, NeoForge skips the jar with a bland "not a valid mod file"
warning that's easy to miss in a 500-line game log.
3. The modId declared in the embedded TOML matches the source folder's
modId. Catches the case where a tweak folder is renamed but its
neoforge.mods.toml isn't updated, which would otherwise ship a jar
whose declared identity differs from its filename.
Each tweak jar's build line now tags "[validated]" so a casual reader
of the log sees that the post-build checks ran. Failure raises a
specific exception with the offending entries listed, so the build
fails loudly at the source instead of producing a pack that mysteriously
doesn't apply its tweaks at runtime.
Stage 5 of Deploy-Brass.ps1 was gated only on \$shouldRunLauncher, so a
"-Stage Pack" run regenerated the manifest locally + mirrored
pack/overrides/ to the share, but never copied the new manifest.json
itself. Result: tweak jars/configs landed on the share, but clients
fetching the (still-old) manifest never knew about the new SHA-1s and
skipped the re-sync. Caught when fixing the brassandsigil_tweaks jar:
the public manifest stayed at 0.9.2 even though local was 0.9.3.
Split into two stages -- launcher exe stays gated on \$shouldRunLauncher,
manifest.json now publishes whenever \$shouldRunPack (so any Pack, All,
or Launcher deploy includes it).
NeoForge's mod scanner rejected brassandsigil_tweaks-1.0.0.jar because
PowerShell 5.1's [ZipFile]::CreateFromDirectory() writes Windows-native
path separators into ZIP entry names on Windows. Entries came out as
"META-INF\neoforge.mods.toml" instead of the spec-required forward-slash
form, so the loader couldn't find the manifest and silently dropped the
jar with "not a valid mod file".
Build-Tweaks.ps1 now opens the archive in 'Create' mode and writes each
file as an explicit ZipArchiveEntry whose name is built from the relative
path with backslashes replaced by forward slashes. Verified the rebuilt
jar lists "META-INF/neoforge.mods.toml" etc.
Pack version 0.9.2 -> 0.9.3 so launchers cached at 0.9.2 see "pack
changed" and re-sync the new tweak jar (their bytes differ; SHA-1 in the
manifest will reflect that).