From d9336db1d53669544edcfad6d31b51bac08da237 Mon Sep 17 00:00:00 2001 From: karl Date: Mon, 12 Oct 2026 21:36:17 +0200 Subject: [PATCH] build: add checked Windows desktop archive packaging --- docs/BUILDING.md | 26 ++++++++++ docs/ROADMAP.md | 5 ++ docs/VALIDATION.md | 7 +++ tools/package_windows.py | 90 +++++++++++++++++++++++++++++++++++ tools/test_package_windows.py | 59 +++++++++++++++++++++++ 5 files changed, 187 insertions(+) create mode 100644 tools/package_windows.py create mode 100644 tools/test_package_windows.py diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 5b9d69c..5e3e767 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -108,6 +108,32 @@ signing/notarization requires Apple tooling and credentials. See the ## CI and packaging gates +### Windows archive for source installations + +After staging the CPU worker and media helpers, build an embedded-frontend +desktop binary and collect its runtime files: + +```powershell +Set-Location apps/desktop +npm run tauri -- build --no-bundle +Set-Location ../.. +python tools/package_windows.py +``` + +The generated `.searchi/packages/searchi-windows.zip` contains the desktop, +matching-architecture Google worker, FFmpeg/FFprobe and notices. It excludes +model caches, local settings and indexes. `PACKAGE.json` records SHA-256 for +each included file. Extract the entire archive before launching `searchi.exe`. +First launch uses normal verified model setup. WebView2 and the applicable +Microsoft C++ runtime remain Windows prerequisites. + +This is an unsigned development archive, not a production installer. Native +launch, clean-machine dependencies, upgrades and signatures must still be +verified. The packager rejects mixed architectures and preserves a previous +archive if validation fails. It does not certify GPU dependency packaging. + +### CI status and installer gates + Gitea Actions are disabled for this repository at the owner's request after repeated failure emails (2026-10-12). Existing workflows remain as references: GitHub defines native OS matrices; Gitea targets its available Ubuntu runner. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index e692b31..6d31d5d 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -49,6 +49,11 @@ Status: implementation started; no production release yet. Windows VM tests use - [ ] Isolated extraction workers with timeouts and resource ceilings. ## 5. Release gates +- [x] Windows desktop archive packager includes explicit runtime/helper files + and notices, checks architecture and records per-file checksums; excludes + model caches and user data. Controlled packaging regression tests pass. +- [ ] Verify embedded-frontend Release archive launch outside the source tree, + clean-machine prerequisites, GPU dependencies, upgrades and signing. - [x] Preflight native license and the complete offline Google model pair before modifying staged resources; corrupted/missing assets preserve existing worker. - [ ] Atomic resource staging and interrupted-copy recovery for release bundles. diff --git a/docs/VALIDATION.md b/docs/VALIDATION.md index 9da6f92..8a64c81 100644 --- a/docs/VALIDATION.md +++ b/docs/VALIDATION.md @@ -7,6 +7,13 @@ and `SEARCHI_FORCE_CPU=1`. ## Current integration checkpoint (2026-10-12) +The Windows archive packager has two controlled Python regressions: complete +required file collection with checksum verification and user-settings exclusion, +and mismatched worker architecture preserving the previous archive. Both pass. +An actual CPU-only Tauri embedded-frontend Release build has been started; +archive creation, native launch outside the source tree and clean-machine +installation remain unverified until its completion and separate checks. + Offline staging now verifies the native license and every bundled Google asset before modifying resources. Two Python regressions verify missing-model rejection and same-size corruption in the second model leaving the existing staged worker diff --git a/tools/package_windows.py b/tools/package_windows.py new file mode 100644 index 0000000..54e2f4c --- /dev/null +++ b/tools/package_windows.py @@ -0,0 +1,90 @@ +"""Build a Windows desktop archive from already compiled, staged resources. + +This packages an unsigned development build; it does not publish or certify +an installer. No model cache, user settings or local index enters the archive. +""" +import argparse +import hashlib +import json +import os +from pathlib import Path +import struct +import tempfile +import zipfile + +ROOT = Path(__file__).resolve().parents[1] + + +def pe_machine(path): + with path.open("rb") as stream: + header = stream.read(64) + if len(header) != 64 or header[:2] != b"MZ": + raise ValueError(f"Not a Windows executable: {path.name}") + offset = struct.unpack_from(" path.stat().st_size - 6: + raise ValueError(f"Invalid executable header: {path.name}") + stream.seek(offset) + signature = stream.read(6) + if signature[:4] != b"PE\0\0": + raise ValueError(f"Invalid PE signature: {path.name}") + return struct.unpack_from("