FIX: QVAC (QuantumVerse Automatic Computer) Packing
CI / test (push) Successful in 2m38s
Release rolling / release (push) Failing after 6m17s

This commit is contained in:
Raven Scott
2026-07-30 14:17:06 -04:00
parent e2d909eaaa
commit bce96d6550
16 changed files with 1391 additions and 441 deletions
+21 -4
View File
@@ -41,22 +41,38 @@ Manual inputs: `skip_client`, `server_hosts`, `client_hosts`, `dry_run`.
## Local parity
```bash
npm install
npm ci # includes @qvac/sdk for desktop LLM packaging
SKIP_INTEGRATION=1 npm test
# Server (Linux Bare)
npm run make:server:linux-x64
# Client (Electron)
# Client (Electron) — ships QVAC Bare worker via @qvac/sdk/electron-forge
npm run make:client:linux-x64
# Full matrix (slow)
# Tools-only client (skip native QVAC worker / larger natives)
PEARDATA_SKIP_QVAC=1 npm run make:client:linux-x64
# Full matrix (slow; QVAC raises client package time)
npm run make
# Stage release archives without upload
DRY_RUN=1 bash scripts/gitea-rolling-release.sh
```
## QVAC in release clients
| Item | Detail |
|------|--------|
| Dependency | `@qvac/sdk` in `package.json` **dependencies** (must install under this repo — not a parent hoist) |
| Forge plugin | `@qvac/sdk/electron-forge` + `@electron-forge/plugin-base` |
| Config | `qvac.config.json` — LLM plugin only |
| Asar | Forced **off** when QVAC packaging is enabled (Bare needs real paths) |
| Skip | `PEARDATA_SKIP_QVAC=1` → tools-only client |
| Docs | [QVAC.md](./QVAC.md) · [Electron tutorial](https://docs.qvac.tether.io/tutorials/electron) |
Client package default timeout is **20 minutes** when QVAC is enabled (`PEARDATA_CLIENT_TIMEOUT_MS`).
## Key scripts
| Script | Role |
@@ -66,10 +82,11 @@ DRY_RUN=1 bash scripts/gitea-rolling-release.sh
| `scripts/make.cjs` | Orchestrate server/client builds |
| `scripts/bare-standalone.cjs` | Pack Bare `peardata-server` |
| `scripts/build-client-bundle.cjs` | esbuild GUI → `electron/app.bundle.cjs` |
| `scripts/build-qvac-worker.cjs` | Local `bundleSdk` for QVAC Bare worker |
| `scripts/predownload-electron.cjs` | Pre-fetch Electron zips for CI |
| `scripts/sign-macos-app.cjs` | Darwin client codesign |
| `scripts/gitea-rolling-release.sh` | Build + stage + Gitea upload |
| `forge.config.cjs` | Electron Forge packaging |
| `forge.config.cjs` | Electron Forge + optional `QvacForgePlugin` |
## Integration tests in CI
+1
View File
@@ -12,6 +12,7 @@ The client shell is a **Pear desktop application** built with `pear-electron` +
| `ui/dashboard.js` | Charts tab master metrics wall |
| `ui/data-manager.js` | Settings → Data (retention / prune / storage usage) |
| `ui/logs.js` | System Log tab (journal default for admins) |
| `ui/qvac/*` | QVAC local AI tab (onboarding + tools; needs `@qvac/sdk` in this project) |
| `shared/taxonomy.js` | Section grouping for the metrics wall |
| `shared/container-names.js` | Human Docker/cgroup labels for the wall |
| `shared/format.js` | Overview KPI unit scaling |
+108 -62
View File
@@ -1,27 +1,117 @@
# QVAC integration (local AI)
PearDatas **QVAC** tab is a local-first SRE copilot. Inference runs on the **desktop** (Electron/Pear); the agent only serves metrics over existing P2P RPC / REST. No cloud LLM is required.
PearDatas **QVAC** tab is a local-first SRE copilot. Inference runs on the **desktop** (Electron / Pear); the agent only serves metrics over existing P2P RPC / REST. No cloud LLM is required.
Upstream: [tetherto/qvac](https://github.com/tetherto/qvac) · [docs.qvac.tether.io](https://docs.qvac.tether.io)
Upstream: [tetherto/qvac](https://github.com/tetherto/qvac) · [docs.qvac.tether.io](https://docs.qvac.tether.io) · [Electron packaging tutorial](https://docs.qvac.tether.io/tutorials/electron)
## Architecture
```
Desktop QVAC tab
→ ui/qvac (engine + tools + onboarding)
→ @qvac/sdk (optional) OR tools-only fallback
→ @qvac/sdk (+ Bare worker) OR tools-only fallback
→ manager.request(Methods.*)
→ PearMonitor agent
```
| Layer | Responsibility |
|-------|----------------|
| Desktop | Model download/load, chat UI, tool loop |
| Desktop | Model download/load, chat UI, tool loop, Bare worker |
| Agent | Lean composite reads (`getHostSnapshot`, `searchCharts`, `summarizeChart`) + existing metrics RPCs |
| REST | `/api/v3/ai/*` mirrors for scripts |
Agent overhead is unchanged when the QVAC tab is unused (no model load on the agent).
## Why `pear run` worked but CI releases did not
| Environment | How `@qvac/sdk` was resolved |
|-------------|------------------------------|
| **`pear run -d .` on a dev machine** | Often found a **hoisted** install (e.g. `~/node_modules/@qvac/sdk`) even when the project did not declare the dependency |
| **CI Electron client** | Clean `npm ci` in the repo — **no `@qvac/sdk`**, no Bare worker entry, asar packing blocked natives |
CI / rolling releases only ship what is in **this** packages `dependencies` + forge output. Dev must not rely on parent `node_modules`.
## Packaging (Electron / CI)
### Dependencies
```json
"dependencies": {
"@qvac/sdk": "^0.16.0"
},
"devDependencies": {
"@electron-forge/plugin-base": "^7.11.2"
}
```
`@electron-forge/plugin-base` is the peer for `@qvac/sdk/electron-forge`.
### Config
`qvac.config.json` lists **only** the plugins PearData needs (keeps the worker smaller):
```json
{
"plugins": ["@qvac/sdk/llamacpp-completion/plugin"]
}
```
### Forge plugin
`forge.config.cjs` loads `QvacForgePlugin` when the SDK is installed. On package it:
1. Runs `bundleSdk` + `verifyBundle` for the target `platform-arch`
2. Forces **`asar: false`** (Bare cannot load `.bare` addons from asar)
3. Tree-shakes unused `@qvac/*` addons and prunes foreign prebuilds
Official caveats: [Electron tutorial → packaging](https://docs.qvac.tether.io/tutorials/electron#step-4-package-for-distribution).
### Escape hatch
```bash
PEARDATA_SKIP_QVAC=1 npm run make:client:linux-x64
```
Produces a **tools-only** client (no LLM natives). QVAC tab still works via RPC tools.
### Local parity with CI
```bash
npm ci # installs @qvac/sdk into THIS project
npm run build:client-bundle
npm run build:qvac-worker # optional local bare-pack
npm run make:client:darwin-arm64 # or any host from scripts/hosts.cjs
```
Increase client package timeout if needed: `PEARDATA_CLIENT_TIMEOUT_MS=1800000`.
### Runtime paths (packaged Electron)
`electron/main.cjs` sets `QVAC_WORKER_PATH` to the first existing:
- `app/qvac/worker.entry.mjs`
- `app/qvac/worker.bundle.js`
- `resources/qvac/...` / asar.unpacked variants
SDK also searches those locations itself ([node-rpc-client](https://github.com/tetherto/qvac)).
## Pear desktop
| Piece | Role |
|-------|------|
| `qvac/worker.pear.entry.mjs` | Bare worker entry (LLM plugin only) |
| `package.json``pear.stage.entrypoints` | Stages the worker for pear |
| `pear.pre` | Stays `pear-electron/pre` (single pipe owner) |
Install deps in the **project** (`npm i` / `npm ci`), not only in a parent folder:
```bash
npm ci
pear run -d .
```
Optional combined pre (advanced): `scripts/pear-pre.mjs` — only if you understand pear-pipe ownership; default remains `pear-electron/pre`.
## Model profiles
| Profile | Chat constant | Tools | Typical use |
@@ -31,17 +121,7 @@ Agent overhead is unchanged when the QVAC tab is unused (no model load on the ag
| Strong | `QWEN3_4B_INST_Q4_K_M` | yes | ≥16 GB RAM |
| Tool-tiny | `LLAMA_TOOL_CALLING_1B_INST_Q4_K` | yes | Fallback |
Embeddings (future RAG): `GTE_LARGE_FP16`.
## Install full local LLM
```bash
npm i @qvac/sdk
```
Without the SDK, the tab still works in **tools-only** mode: it calls agent RPCs and formats grounded answers (no generative model).
Onboarding lives in the QVAC tab (Setup). Preferences: `qvacOnboarded`, `qvacProfile`, `qvacMode` in desktop settings.
Without the SDK (or if load fails), the tab stays in **tools-only** mode: live agent RPCs, no generative model.
## Agent RPCs (viewer)
@@ -51,65 +131,31 @@ Onboarding lives in the QVAC tab (Setup). Preferences: `qvacOnboarded`, `qvacPro
| `searchCharts` | `{ q, limit }` catalog search |
| `summarizeChart` | `{ chart, after?, points? }` min/avg/max/last per dim |
### REST
- `GET /api/v3/ai/snapshot`
- `GET /api/v3/ai/charts?q=&limit=`
- `GET /api/v3/ai/chart/:id/summary?after=&points=`
REST: `GET /api/v3/ai/snapshot`, `/api/v3/ai/charts`, `/api/v3/ai/chart/:id/summary`.
## Tools the chat can call
| Tool | Purpose |
|------|---------|
| `host_snapshot` | Health + KPIs + anomalies |
| `search_charts` / `summarize_chart` / `query_metric` | Catalog + series |
| `list_anomalies` / `list_alerts` | Alerts surface |
| `list_processes` | Process table |
| `query_logs` | Journal / anomaly / audit |
| `fleet_health` | Parent fleet summary |
| `storage_info` | Retention + disk usage |
| `local_knowledge` | Keyword RAG over guide + catalog (desktop) |
| `open_chart` / `open_view` | UI navigation |
| `silence_alert` | Operator + confirm dialog |
## Local knowledge (RAG)
Without embedding models, PearData uses **keyword retrieval** over:
- Built-in user-guide snippets (`ui/qvac/rag.js`)
- Live chart catalog titles/contexts
Context is injected into the system prompt when **Settings → QVAC → Inject local knowledge** is on (default).
`host_snapshot`, `search_charts`, `summarize_chart`, `query_metric`, `list_anomalies`, `list_alerts`, `list_processes`, `query_logs`, `fleet_health`, `storage_info`, `local_knowledge`, `open_chart`, `open_view`, `silence_alert` (operator + confirm).
## Settings
| Pref | Default | Meaning |
|------|---------|---------|
| `qvacProfile` | recommended | Lite / Recommended / Strong / Tool-tiny |
| `qvacRag` | true | Inject local knowledge |
| `qvacIdleUnloadMin` | 30 | Unload model from RAM after idle minutes (0 = never) |
| `qvacOnboarded` | false | Setup wizard completed |
## Desktop settings
| Key | Default | Meaning |
|-----|---------|---------|
| `qvacOnboarded` | `false` | Setup wizard completed |
| `qvacProfile` | `recommended` | Model profile id |
| `qvacMode` | `''` | `qvac` \| `fallback` after last load |
| `qvacRag` | `true` | Inject guide + catalog snippets into prompts |
| `qvacRag` | `true` | Inject guide + catalog snippets |
| `qvacIdleUnloadMin` | `30` | Unload LLM after idle minutes (`0` = never) |
UI: **Settings → QVAC** and the QVAC tab header (Unload / Setup / New chat).
## Pear / Bare notes
- Electron: `@qvac/sdk` spawns a Bare worker automatically.
- Pear: stub entry at `qvac/worker.pear.entry.mjs` (listed in `package.json``pear.stage.entrypoints`). Install `@qvac/bare-sdk` + `@qvac/llm-llamacpp` and uncomment plugin registration when enabling Pear-native inference.
## Related files
- `ui/qvac/*` — desktop UI + engine
- `server/services/ai-tools.js` — composite reads
- `shared/protocol.js` — method roles
- `user-guide/qvac.md` — operator walkthrough
| Path | Role |
|------|------|
| `ui/qvac/*` | Desktop UI + engine |
| `qvac.config.json` | Plugin allow-list for bundling |
| `qvac/worker.entry.mjs` | Electron/Node worker entry |
| `qvac/worker.pear.entry.mjs` | Pear worker entry |
| `forge.config.cjs` | `QvacForgePlugin` + ignore rules |
| `scripts/build-qvac-worker.cjs` | Local `bundleSdk` |
| `server/services/ai-tools.js` | Agent composite reads |
| `user-guide/qvac.md` | Operator walkthrough |
+4
View File
@@ -54,8 +54,12 @@ Env knobs:
| `PEARDATA_CLIENT_HOSTS` | all 64-bit | Client host list |
| `PEARDATA_SKIP_CLIENT=1` | off | Server-only release |
| `PEARDATA_SKIP_REBUILD=1` | on in CI | Skip `@electron/rebuild` |
| `PEARDATA_SKIP_QVAC=1` | off | Tools-only Electron client (no Bare LLM worker) |
| `PEARDATA_CLIENT_TIMEOUT_MS` | `1200000` with QVAC / `600000` without | Per-host client package timeout |
| `DRY_RUN=1` | off | Stage archives, skip upload |
Desktop clients ship **QVAC** (`@qvac/sdk` + forge plugin) unless `PEARDATA_SKIP_QVAC=1`. See [QVAC.md](./QVAC.md) and [CI.md](./CI.md).
## CI / forge pipelines
| Forge | Workflow | Trigger | Output |