docs(desktop): document source provenance and runtime boundaries

This commit is contained in:
abraxas914 committed 2026-08-23 18:15:52 +08:00
1 parent bbc410b47b
commit dbdc63c368
2 files changed
+194 -19

No files matched your search

+96
View File
@@ -0,0 +1,96 @@
# GenericAgent Desktop 2.0 integration boundary
GenericAgent Desktop 2.0 is a packaged Tauri desktop application with a generated React renderer and
Desktop-specific Python services. The React source is intentionally developed outside this upstream tree;
the generated distribution and all runtime interfaces required to execute it are tracked here.
## Renderer ownership
- `frontends/desktop/dist/**` contains the generated Desktop 2.0 HTML, JavaScript, CSS, fonts, and images.
- `frontends/desktop/static/**` is the independent Desktop v1 implementation and remains available unchanged.
- Tauri packages `dist/**`; it does not compile React during an upstream build.
- The public React source, issue tracker, and contribution home is
<https://github.com/abraxas914/GenericAgent>.
- The exact fork commit and generated-file content manifest are recorded in
`dist/build-provenance.json`.
Generated files must not be edited by hand. Renderer changes are made and tested in the fork, rebuilt from an
accepted fork `main` commit, and submitted upstream as a refreshed `dist/**` tree with matching provenance.
The manifest identifies the submitted bytes; it is not a claim that later builds are bit-for-bit reproducible.
The production Tauri configuration loads only the tracked asset origin and applies an explicit Content Security
Policy. React source tooling is absent from the upstream package path, while WebDriver permission remains isolated
to `tauri.e2e.conf.json` and is not granted by the production configuration.
## Desktop runtime ownership
Desktop 2.0 uses these repository-owned integration layers:
- `frontends/desktop_bridge.py`: local HTTP/WebSocket API, model/session/upload/data routes, service control,
identity, and Desktop diagnostics.
- `frontends/conductor.py`: Desktop collaboration and model-routing integration.
- `frontends/cost_tracker.py`: Desktop usage and cost ledger.
- `frontends/data_backup.py`: validated Desktop data export, inspection, and import/merge behavior.
- `frontends/desktop_settings.py`: locked, atomic read/modify/write updates for shared Desktop preferences.
- `frontends/desktop/src-tauri/**`: native bootstrap, permissions, file pickers, runtime/source switching,
process/port recovery, window behavior, and package resource resolution.
The package-owned bridge remains the executable service boundary. `GA_ROOT` can point it at a compatible
external GenericAgent repository, but does not replace the package-owned bridge or Tauri shell.
Desktop data import first backs up the complete destination `memory/**` tree, then applies source-wins memory
files. Model responses remain add-only, and Desktop sessions are de-duplicated by session ID. Activation is staged
and rolled back on failure. Import is rejected while a managed session or Desktop extra has unfinished work; users
must also stop any independent TUI, CLI, or automation process before importing because those external processes
are outside the bridge's maintenance gate. The persistent cost ledger is initialized by the Desktop bridge only;
existing TUI and conductor processes retain their previous in-memory accounting hot path.
Browser-origin requests are accepted only from the production Tauri origins, the fixed development origin, the
explicit E2E origin, or the bridge's own same origin. Native clients without an Origin remain supported, while
cross-site, null, lookalike, wrong-port, preflight, and WebSocket requests are rejected before route handling.
Backup exports cannot be written into any managed data or HTTP-readable directory.
Managed-service state is based on the bridge-owned live child process, not merely a listener on the configured
port. A foreign conductor on production port `8900` is reported as an external port conflict and is never stopped
or counted as an owned running extra. The alternate conductor port is available only to the isolated package E2E
journey; production renderer and CSP contracts remain fixed to `8900`.
On macOS, the package runtime uses a stable writable root and is refreshed through a package/build/source marker
with staged atomic activation. A previously shipped versioned runtime is migrated into that stable root. User
configuration, memory, responses, sessions, and token ledger data are preserved; a failed migration or activation
restores the previous runtime and marker. Matching markers keep the hot-start copy untouched.
## Core runtime boundary
Desktop 2.0 does not own or modify GenericAgent's Agent/LLM/Harness business runtime. In particular, the
integration does not change `agentmain.py`, LLM execution, Harness/Agent execution, inference, tool-calling,
or memory-scheduling semantics. Desktop bridge and conductor changes translate Desktop requests onto those
existing core contracts.
## Version and release contract
Desktop package metadata is `0.2.0` across npm, Cargo, Tauri, and generated provenance. Upstream packages consume
the tracked `dist/**` tree, so an upstream maintainer can build official Windows, Linux, and macOS artifacts
without the React source. A `desktop-portable-*` tag starts three read-only platform builders. One separate
publisher receives write permission only after all three succeed, validates the six expected files and checksums,
creates an invisible draft with all assets, and then exposes that single entry as a prerelease. Manual
`workflow_dispatch` runs produce candidate artifacts only and skip the publisher.
The Linux builder runs on Ubuntu 22.04, isolates Rust target/bin caches from newer runner ABIs, and rejects any
ELF requiring a GLIBC version newer than 2.35. Windows remains unsigned and documents SmartScreen plus checksum
verification; macOS remains ad-hoc signed and unnotarized.
The renderer still uses the existing local loopback bridge contract. This integration neither treats that inherited
platform requirement as a new release blocker nor claims to have changed operating-system loopback policy.
## Validation layers
- Compiled distribution contract: required entries, asset references, source-map/source leakage, E2E markers,
version consistency, exact provenance manifest, and the `dist` package entry.
- Python contracts: bridge, conductor, model routing, sessions, uploads, cost ledger, `GA_ROOT`, and data backup.
- Rust contracts: formatting, clippy, production and E2E feature tests, and
path/identity/port/diagnostic/bootstrap behavior.
- Native package contract: Linux Tauri build smoke plus the platform release workflow.
The richer React unit/browser/native E2E suites remain in the fork and run before its accepted `main` SHA is
used to refresh the generated upstream distribution.
+98 -19
View File
@@ -1,20 +1,37 @@
# packaging
# Desktop packaging
桌面端发布相关材料。本目录的内容**不会**整体打进发布包——CI
(`.github/workflows/desktop-release-package.yml`)只从这里挑选 `scripts/` 下的
安装/卸载脚本拷进各平台的发布产物,其余文件对构建打包过程是只读参考。
This directory contains the scripts and locked Python inputs used to assemble GenericAgent Desktop packages.
The directory is not copied wholesale into a release; the workflow selects only the platform scripts and
requirements files required by each package.
## 目录结构
## Submitted renderer boundary
```
Official upstream package jobs consume the tracked `frontends/desktop/dist/**` renderer directly. They install
only the minimal submitted Tauri CLI manifest and do not run Vite, TypeScript, React tests, or any other renderer
source command. Tauri embeds `dist/**` in the native application. The portable `runtime/app` copy deliberately
excludes `dist/**` so the same renderer is not duplicated as loose runtime data.
The React source, issue tracker, and contribution home is
<https://github.com/abraxas914/GenericAgent>. The exact accepted fork commit and generated content manifest are
recorded in `dist/build-provenance.json`. `frontends/desktop/static/**` remains the independent Desktop v1 and is
unchanged by Desktop 2.0 packaging.
The Semi Design MIT text is tracked as `dist/THIRD_PARTY_NOTICES.txt`. Root attributes force the source notice and
compiled notice to LF on every platform, and all three package builders verify the locked notice SHA-256 before
building.
## Inputs
```text
frontends/desktop/packaging/
├── README.md # 本说明
├── CHECKLIST.md # 发布前功能测试清单(测试协调用,不参与打包)
├── TODO.md # 各平台测试分工与计划(测试协调用,不参与打包)
└── scripts/ # ← 唯一被 CI 消费的内容
├── README.md
├── dmg-build-requirements.txt
├── python-runtime-requirements.txt
└── scripts/
├── merge_desktop_settings.py
├── windows/
│ ├── install_windows.ps1 # 环境准备脚本
│ ├── uninstall.bat # 卸载入口(向用户确认后调用 ps1)
│ ├── install_windows.ps1
│ ├── uninstall.bat
│ └── uninstall_windows.ps1
├── linux/
│ ├── install_linux.sh
@@ -24,12 +41,74 @@ frontends/desktop/packaging/
└── uninstall.command
```
## CI 如何使用这些脚本
- Node is fixed at `22.23.2`; the compiled-only jobs install exactly `@tauri-apps/cli` `2.11.4` with
`npm install --package-lock=false`, assert that no source lockfile was created, and never invoke Vite. Rust is
fixed at `1.95.0` and crates are locked by `Cargo.lock`.
- Root `.gitattributes` pins both the source `public/THIRD_PARTY_NOTICES.txt` path and the delivered
`dist/THIRD_PARTY_NOTICES.txt` path to LF; the source file itself stays outside this compiled-only PR. Each of
the three builders runs the cross-platform compiled-distribution contract immediately before Tauri embeds the
tracked `dist`, locking the notice SHA-256 to
`2acf865e87e59090121369aac0575467067fdd7999923a70d785a46ceae3330f` and failing on any byte drift.
- python-build-standalone is fixed at release `20260814`, CPython `3.12.14`, an explicit architecture, and an
archive SHA-256 on each platform.
- The macOS builder runs on the Apple-silicon `macos-15` host and uses host CPython `3.12.10` only for the
hash-locked DMG layout tools. That host interpreter is separate from the embedded `3.12.14` runtime.
- Windows converts `RUNNER_TEMP` with `cygpath -u` before passing its archive path to POSIX tools.
- Linux builds on Ubuntu 22.04, uses a dedicated glibc-2.35 Rust cache prefix with target/bin caching disabled,
and scans every packaged ELF to reject a maximum GLIBC requirement above 2.35.
- Runtime direct and transitive dependencies use exact versions in `python-runtime-requirements.txt`; downloads
require binary wheels. The DMG layout requirements use exact versions and wheel hashes.
- Preparation disables Python bytecode writes and removes `__pycache__`, `.pyc`, and `.pyo` files across the
complete bundled runtime without removing vendored Python packages.
- Checkout, Node/Python setup, artifact upload/download, Rust toolchain, and Rust cache actions use full commit
SHA pins and disable persisted checkout credentials.
`desktop-release-package.yml` 在打各平台 portable 包时,把对应平台的脚本
`cp` 进发布目录(例如 Windows 包里放 `install_windows.ps1` /
`uninstall.bat` / `uninstall_windows.ps1`)。**修改安装/卸载行为只需改
`scripts/` 下的文件,不需要动 workflow。**
These controls do not make the packages bit-for-bit reproducible. Runner images, Ubuntu packages, the Windows
SDK/UCRT input, platform wheels, and native packaging metadata can change or contain timestamps. Candidate
artifact SHA-256 values and real-package journeys remain the evidence for a particular build.
> 说明:实际的桌面壳二进制(`GenericAgent.exe` / `.AppImage` / `.app`)由 CI
> 构建生成并发布到 GitHub Release,不在本仓库内提交,也不在本目录占位。
## Candidate artifacts and publication
Manual `workflow_dispatch` runs build the selected platform or all three platforms as downloadable Actions
artifacts. They never create or edit a GitHub Release.
A maintainer-created `desktop-portable-*` tag starts this publication graph:
```text
Windows builder (contents: read) ─┐
Linux builder (contents: read) ─┼─ verified Actions artifacts ─┐
macOS builder (contents: read) ─┘ │
▼
publisher (contents: write)
validate six files/checksums
create one invisible draft
verify uploaded asset set
expose one prerelease
```
The three builders do not receive a write token and do not call the GitHub Release API. The publisher runs only
for a matching tag push after all three builders succeed; it does not check out source or run package tooling.
It refuses to overwrite an existing Release for the tag.
The prerelease contains exactly:
- `GenericAgent-Desktop-Windows-Portable.zip`
- `SHA256SUMS-windows.txt`
- `GenericAgent-Desktop-Linux-Portable.tar.gz`
- `SHA256SUMS-linux.txt`
- `GenericAgent-Desktop-macOS-aarch64.dmg`
- `GenericAgent-Desktop-macOS-aarch64.dmg.sha256`
The macOS application is ad-hoc signed only. It is not Developer ID signed or notarized, and the published notes
retain the documented context-menu / Privacy & Security opening path.
## Validation
- `npm run test:dist` verifies required compiled entries, references, source leakage, dead assets, the notice hash,
version/CSP/E2E isolation, source provenance, and the atomic release contract.
- `python -m pytest frontends/tests` verifies Desktop bridge, conductor, model/session/upload behavior, the
Desktop-only cost ledger, transactional data import, package-evidence parsing, owned service/port behavior,
`GA_ROOT`, and Tauri security contracts.
- Rust formatting, clippy, production/E2E tests, and a Tauri `--no-bundle` build validate the native shell against
the tracked renderer.
- Shell, Python, PowerShell, YAML, action pinning, boundary diff, and conflict checks run before delivery.