@wenathlan/saddle 2.1.3 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Dockerfile CHANGED
@@ -13,7 +13,7 @@
13
13
  # compute service published as ghcr.io/wenathlan/saddle:<version>
14
14
  # across the four-arch family standard (amd64, arm64, ppc64le, s390x
15
15
  # — the trixie slim base line; the stage also builds the web SPA so
16
- # the image serves the self-hosted console via `node /app/web/server.js`).
16
+ # the image serves the self-hosted console via `node /app/web/server.ts`).
17
17
  #
18
18
  # saddle v2 (grand merge) - virtual hardware engine, multi-stage, multi-arch image.
19
19
  #
@@ -94,7 +94,7 @@
94
94
  # -v vmdata:/data/vmdata -v webdata:/data/web \
95
95
  # -v ./vm.config.json:/engine/vm.config.json:ro \
96
96
  # -e PORT=8080 -e NODE_ENV=production -p 31280:8080 \
97
- # ghcr.io/wenathlan/saddle:vhe-2.1.3
97
+ # ghcr.io/wenathlan/saddle:vhe-2.1.5
98
98
  #
99
99
  # vheqemu (the guest runner; build it first with
100
100
  # docker build --target qemu-runtime -t saddle/qemu:11.1.0 . because the
@@ -128,7 +128,7 @@
128
128
  # -e VHE_GPU_PROFILE=b200 -e VHE_GPUS=8 -e VHE_MIG=1 \
129
129
  # -e VHE_SMI_DRIVER=575.57.08 -e VHE_SMI_CUDA=12.9 \
130
130
  # -e VHE_SMI_INTERVAL=30 -e VHE_SKIP_XVFB=1 -e VHE_SKIP_VALIDATE=1 \
131
- # ghcr.io/wenathlan/saddle:vhe-2.1.3 /bin/bash -c '
131
+ # ghcr.io/wenathlan/saddle:vhe-2.1.5 /bin/bash -c '
132
132
  # while true; do
133
133
  # /usr/local/bin/nvidia-smi "$VHE_GPU_PROFILE" "$VHE_GPUS" || true
134
134
  # sleep "$VHE_SMI_INTERVAL"
@@ -145,7 +145,7 @@
145
145
  # -v qemudata:/data/qemudata \
146
146
  # -v ./qemubridge.py:/engine/qemubridge.py:ro \
147
147
  # -e QMP_SOCKET=/run/vhe/vm.qmp -e PYTHONUNBUFFERED=1 \
148
- # ghcr.io/wenathlan/saddle:vhe-2.1.3 \
148
+ # ghcr.io/wenathlan/saddle:vhe-2.1.5 \
149
149
  # python3 /engine/qemubridge.py --socket /run/vhe/vm.qmp status
150
150
  #
151
151
  # saddle-node (the node-engine service, the former compose.yml
@@ -159,7 +159,7 @@
159
159
  # --log-driver json-file --log-opt max-size=50m --log-opt max-file=5 \
160
160
  # --tmpfs /tmp:size=2g,mode=1777 \
161
161
  # -e SADDLE_MEMORY_ENGINE=ram -e SBOT_PLATFORM= -e SBOT_CDN_URL= \
162
- # ghcr.io/wenathlan/saddle:2.1.3 \
162
+ # ghcr.io/wenathlan/saddle:2.1.5 \
163
163
  # node dist/cli.js plan
164
164
  #
165
165
  # observability (the former prometheus scraper of the full profile)
@@ -902,10 +902,10 @@ COPY qemu.config mttg.config passage.config docker.config /engine/
902
902
  # the web node ships inside the main container: the mesh edition (auth,
903
903
  # sqlite database, dashboard and the browser sandbox pages) runs from the
904
904
  # same image, so one container serves the engine AND the web surface.
905
- # run it with: docker run ghcr.io/wenathlan/saddle node /engine/web/server.js
905
+ # run it with: docker run ghcr.io/wenathlan/saddle node /engine/web/server.ts
906
906
  COPY web /engine/web
907
907
  # the built web SPA (vite, from the saddle-build stage): the console
908
- # server (node /engine/web/server.js) serves web/dist/public - the
908
+ # server (node /engine/web/server.ts) serves web/dist/public - the
909
909
  # unified React interface that absorbed the former static pages.
910
910
  COPY --from=saddle-build /app/web/dist /engine/web/dist
911
911
 
@@ -1271,7 +1271,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --start-interval=5s
1271
1271
  # OCI labels for registry introspection.
1272
1272
  LABEL org.opencontainers.image.title="saddle virtual-hardware engine (the grand merge)" \
1273
1273
  org.opencontainers.image.description="100% software virtual hardware: per-profile CPU/memory spoofing via LD_PRELOAD (max/balanced/lite), mesa 26.2.1 llvmpipe/lavapipe/rusticl, QEMU 11.1.0 TCG/MTTCG, virtual nvidia-smi adapter + NVML/CUDA shims, node 26.7.0, python bridge" \
1274
- org.opencontainers.image.version="2.1.3" \
1274
+ org.opencontainers.image.version="2.1.5" \
1275
1275
  org.opencontainers.image.licenses="MIT" \
1276
1276
  org.opencontainers.image.source="https://github.com/wenathlan/saddle" \
1277
1277
  org.opencontainers.image.documentation="https://github.com/wenathlan/saddle/blob/main/README.md" \
@@ -1359,7 +1359,7 @@ RUN apt-get update \
1359
1359
  COPY --from=saddle-build /app/dist ./dist
1360
1360
  # the web service surface (self-hosted console): the built SPA
1361
1361
  # (web/dist/public from the saddle-build vite run) plus the pure-node
1362
- # server stack (server.js, db.js, auth.js, mesh.js, sandbox.js,
1362
+ # server stack (server.ts, db.ts, auth.ts, mesh.ts, sandbox.ts,
1363
1363
  # mime.types, init.sql, schema.prisma) - zero npm dependencies, the
1364
1364
  # node 26 runtime carries everything (node:sqlite, node:crypto).
1365
1365
  COPY --from=saddle-build /app/web ./web
package/README.md CHANGED
@@ -30,7 +30,7 @@ domain modules land beside the saddle domains:
30
30
  | `scheduler.ts`, `compute.ts`, `performance.ts` | job queues, batch compute and benchmark planning |
31
31
  | `media.ts`, `render.ts`, `quantum.ts`, `tiers.ts` | media pipeline, GPU registry, quantum simulation, tier policy |
32
32
  | `security.ts`, `alternatives.ts` | hardening gates and the alternative-stack catalog |
33
- | `web/` | the static console and the zero-dependency self-hosted API (`node web/server.js`) |
33
+ | `web/` | the static console and the zero-dependency self-hosted API (`node web/server.ts`) |
34
34
  | `specs/*` package exports | processors, gpus, cores, boards and the qemu/mttg/passage/docker envelopes |
35
35
 
36
36
  The full pre-merge documentation of the engine lives in
package/boards.json CHANGED
@@ -88,7 +88,7 @@
88
88
  }
89
89
  },
90
90
  "name": "boards.json",
91
- "version": "2.1.3",
91
+ "version": "2.1.5",
92
92
  "title": "saddle - Virtual Motherboard Database (retail boards + platform reference sockets)",
93
93
  "sources": [
94
94
  "pool:boards.json [S6, 20 retail boards]",
package/cores.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "metadata": {
3
3
  "id": "cores.json",
4
- "version": "2.1.3",
4
+ "version": "2.1.5",
5
5
  "date": "2026-08-22",
6
6
  "datestamp": "2026-08-22T00:00:00Z",
7
7
  "observer": "third person observer notes the hybrid core inventory reflects production silicon as of 2026-08-22",
package/docker.config CHANGED
@@ -2,7 +2,7 @@
2
2
  "meta": {
3
3
  "name": "docker.config",
4
4
  "title": "saddle - Docker Engine and Containerization Configuration",
5
- "version": "2.1.3",
5
+ "version": "2.1.5",
6
6
  "date": "2026-08-22",
7
7
  "language": "en",
8
8
  "sources": [
@@ -618,7 +618,7 @@
618
618
  "labels": {
619
619
  "org.opencontainers.image.title": "saddle-v6",
620
620
  "org.opencontainers.image.description": "Saddle v6 virtualization orchestrator with QEMU 11.1.0, Node 22 LTS, Python 3.13.5, MTTG, Passage, OVMF",
621
- "org.opencontainers.image.version": "2.1.3",
621
+ "org.opencontainers.image.version": "2.1.5",
622
622
  "org.opencontainers.image.created": "2026-08-22T00:00:00Z",
623
623
  "org.opencontainers.image.authors": "Saddle Core <core@saddle.dev>",
624
624
  "org.opencontainers.image.url": "https://saddle.dev",
@@ -630,7 +630,7 @@
630
630
  "org.opencontainers.image.base.name": "debian:bookworm-slim",
631
631
  "org.opencontainers.image.base.digest": "sha256:bookworm-slim-pinned-2026-08-22",
632
632
  "saddle": {
633
- "com.saddle.version": "2.1.3",
633
+ "com.saddle.version": "2.1.5",
634
634
  "com.saddle.engine": "qemu-11.1.0",
635
635
  "com.saddle.modes": "32",
636
636
  "com.saddle.forge.mirrors": "github,gitea,forgejo",
@@ -104,7 +104,7 @@ Line counts are the shipped files (v2 carryover plus the v3/v5/v6 additions); ev
104
104
  | `libs/gpumonitor.cpp` | 1543 | C++26 four-mode build: CLI smi-adapter, NVML/libcuda shim, N-API addon, forge mode (Plan/validate/qemu_argv, Mttg work-stealing mirror) | 12 hooks |
105
105
  | `libs/virtualhardware.c` | 1011 | C11 LD_PRELOAD core: open-family interception, vhe_translate, inotify regeneration thread, xorshift32 drift, constructor 101 | 12 hooks |
106
106
 
107
- Data files: `gpus.json` 2408, `processors.json` 2217, `vm.config.json` 1910, `cores.json` 1801, `mttg.config` 1548, `boards.json` 1517, `passage.config` 1330, `qemu.config` 1061, `virtualhardware.json` 739, `docker.config` 768. Web node (`web/`, the v6 edition plus the v7 wave): `sandbox.js` 1433 is the browser-pure engine port (bank, procfs payloads, the 89-char smi table, mesa summaries, boot dmesg and the command dispatcher), `server.js` 640 serves the console plus the `/api/v1` contract (health, spec catalogs, sandbox lifecycle, exec) over `node:http`, `index.html` 646 renders the spec panel, terminal and bus timeline, adapters `vercel.json`/`netlify.toml`/`caddyfile` (static edge, api reverse proxied) and `readme.md` 120; the v7 wave completes the node with `db.js` (sqlite persistence for users, sessions and sandboxes), `auth.js` (scrypt password hashing, timing-safe verification, cookie sessions), `mesh.js` (HMAC-SHA256 signed clone-to-main calls with replay windows), the `login.html`/`register.html`/`dashboard.html` pages, `package.json`/`Dockerfile` (image `ghcr.io/wenathlan/e2ugh (main image, web/ included)`; node pinned by the root `.nvmrc`), the database definition kept flat as `schema.prisma` plus `init.sql`, and `mime.types`. Total repository: about 62,200 lines across 83 tracked files (the v2 carryover plus the v3 domains, the v5 media/test waves and the v6 web edition; the `tests/` suite alone is 3,674 lines across eleven files).
107
+ Data files: `gpus.json` 2408, `processors.json` 2217, `vm.config.json` 1910, `cores.json` 1801, `mttg.config` 1548, `boards.json` 1517, `passage.config` 1330, `qemu.config` 1061, `virtualhardware.json` 739, `docker.config` 768. Web node (`web/`, the v6 edition plus the v7 wave): `sandbox.ts` 1433 is the browser-pure engine port (bank, procfs payloads, the 89-char smi table, mesa summaries, boot dmesg and the command dispatcher), `server.ts` 640 serves the console plus the `/api/v1` contract (health, spec catalogs, sandbox lifecycle, exec) over `node:http`, `index.html` 646 renders the spec panel, terminal and bus timeline, adapters `vercel.json`/`netlify.toml`/`caddyfile` (static edge, api reverse proxied) and `readme.md` 120; the v7 wave completes the node with `db.ts` (sqlite persistence for users, sessions and sandboxes), `auth.ts` (scrypt password hashing, timing-safe verification, cookie sessions), `mesh.ts` (HMAC-SHA256 signed clone-to-main calls with replay windows), the `login.html`/`register.html`/`dashboard.html` pages, `package.json`/`Dockerfile` (image `ghcr.io/wenathlan/e2ugh (main image, web/ included)`; node pinned by the root `.nvmrc`), the database definition kept flat as `schema.prisma` plus `init.sql`, and `mime.types`. Total repository: about 62,200 lines across 83 tracked files (the v2 carryover plus the v3 domains, the v5 media/test waves and the v6 web edition; the `tests/` suite alone is 3,674 lines across eleven files).
108
108
 
109
109
  ## 3a. v3 redistribution: features live in domains
110
110
 
@@ -129,7 +129,7 @@ Tests live in the `tests/` directory (one of the five allowed directories) and r
129
129
 
130
130
  ## 3c. Web node architecture (v7)
131
131
 
132
- The web node is a static edge plus one self-hosted process. Clones (Vercel and Netlify static deploys of the `web/` pages, redeployed from the `pages.yml` zip -9 bundle) ship only immutable assets: the console, the auth pages and `sandbox.js`, which runs the whole engine client-side and keeps working with no backend. The main node (`node web/server.js` behind the `caddyfile` on devthink.pro, packaged as `ghcr.io/wenathlan/e2ugh (main image, web/ included)`) owns everything stateful: `db.js` opens the sqlite file (`schema.prisma`/`init.sql` define it, kept flat per the two-level contract), `auth.js` is the auth authority - scrypt password hashing with per-user salts, timing-safe verification and server-side sessions delivered as `HttpOnly` cookies - and `mesh.js` verifies the HMAC-SHA256 signature (method, path, body digest, timestamp, bounded replay window) that every clone attaches to forwarded calls before routing. The design is deliberately anti-serverless: no function runs on the edge platforms, clones hold no secrets and no database, and unauthenticated clones receive 401 from the main node instead of any partial authority.
132
+ The web node is a static edge plus one self-hosted process. Clones (Vercel and Netlify static deploys of the `web/` pages, redeployed from the `pages.yml` zip -9 bundle) ship only immutable assets: the console, the auth pages and `sandbox.ts`, which runs the whole engine client-side and keeps working with no backend. The main node (`node web/server.ts` behind the `caddyfile` on devthink.pro, packaged as `ghcr.io/wenathlan/e2ugh (main image, web/ included)`) owns everything stateful: `db.ts` opens the sqlite file (`schema.prisma`/`init.sql` define it, kept flat per the two-level contract), `auth.ts` is the auth authority - scrypt password hashing with per-user salts, timing-safe verification and server-side sessions delivered as `HttpOnly` cookies - and `mesh.ts` verifies the HMAC-SHA256 signature (method, path, body digest, timestamp, bounded replay window) that every clone attaches to forwarded calls before routing. The design is deliberately anti-serverless: no function runs on the edge platforms, clones hold no secrets and no database, and unauthenticated clones receive 401 from the main node instead of any partial authority.
133
133
 
134
134
  ## 4. One bus, one state machine, one metrics store
135
135
 
@@ -209,7 +209,7 @@ Per-target delivery notes (one line each, from the collapsed topic docs):
209
209
  | Target | How the same library is consumed |
210
210
  | --- | --- |
211
211
  | desktop | EgUi lab UI over the in-process factory; every control honors the 44 px touch target |
212
- | web | browser bundle shipped as the `web/` console (v6): `sandbox.js` mirrors the verified bank, `server.js` serves it and `/api/spec`; zero dependencies keep the graph tree-shakeable |
212
+ | web | browser bundle shipped as the `web/` console (v6): `sandbox.ts` mirrors the verified bank, `server.ts` serves it and `/api/spec`; zero dependencies keep the graph tree-shakeable |
213
213
  | extension | browser extension service worker; endpoints bind a random port, never localhost |
214
214
  | cli | planner CLI: `node --experimental-strip-types index.ts` reading `vm.config.toml` |
215
215
  | android | container/wasm module surface through the JVM bridge; arm64 native runner images |
@@ -7,7 +7,7 @@ The native wrappers — Android, iOS and desktop — are **generated on the CI r
7
7
  - **Generated on the runners, never committed**: the mobile workflows run `npx cap add android` / `npx cap add ios` into `build/native/` (gitignored); the desktop workflow scaffolds the Tauri Rust envelope (Cargo.toml, main.rs, lib.rs, build.rs) via heredoc into `build/native/desktop`. The historical templates remain recoverable from git history.
8
8
  - **Single icon source**: `web/icon.svg` is the one source of every native icon family. Runners derive the Android mipmaps/splashs, the iOS AppIcon set and the Tauri bundle icons from it (`npx cap assets` equivalents and `npx --yes @tauri-apps/cli@2.11.4 icon web/icon.svg --output build/native/desktop/icons`).
9
9
  - **Versions injected via `SADDLE_VERSION` env**: the workflows patch the generated `tauri.conf.json` copy, the Cargo manifest, the Gradle config and the iOS project with the resolved release version at build time — no committed file carries a stale native version.
10
- - **One conversion config at the repository root**: `capacitor.config.ts` (`webDir` = `web/dist/public`, `android.path`/`ios.path` = `build/native/{android,ios}`) and `tauri.conf.json` (`frontendDist` = `web/dist/public`, `bundle.icon` relative to the scaffold directory where the runner copies this config).
10
+ - **One conversion config pair**: `web/capacitor.config.ts` (the web root, where the Capacitor CLI resolves it: `webDir` = `dist/public`, `android.path`/`ios.path` = `../build/native/{android,ios}` at the repository root) and `tauri.conf.json` (the repository root, `frontendDist` = `web/dist/public`, `bundle.icon` relative to the scaffold directory where the runner copies this config).
11
11
 
12
12
  ## Android surface (from the retired `web/android/README.md`)
13
13
 
package/gpus.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "meta": {
4
4
  "name": "gpus.json",
5
5
  "title": "saddle - Unified Virtual GPU Database",
6
- "version": "2.1.3",
6
+ "version": "2.1.5",
7
7
  "date": "2026-08-22",
8
8
  "language": "en",
9
9
  "description": "Union of the v5 GPU database (7 virtual identity identities), the S6 registry (RX 8900 XTX + Arc B770 unique), Blackwell architecture specs v5+v6 (B100/GB200/RTX 5070/5070 Ti SKUs), gpu.config TOML SKUs (incl. 5 AMD APU RDNA iGPUs) and the 11-entry vfio profile table. PCI device id for RTX PRO 6000 corrected 2BB5->26B5 per canonical v5.",
package/mttg.config CHANGED
@@ -2,7 +2,7 @@
2
2
  "meta": {
3
3
  "name": "mttg.config",
4
4
  "title": "saddle - MTTG Multi-Tenant Task Groups (cgroups v2 + tenants + transcode) with MTTCG (QEMU TCG) section",
5
- "version": "2.1.3",
5
+ "version": "2.1.5",
6
6
  "date": "2026-08-22",
7
7
  "language": "en",
8
8
  "conceptSeparation": "MTTG = Multi-Tenant Task Groups (cgroup v2 cpu.weight/cpuset/memory/io/pids/hugetlb/rdma + tenants + transcode pipelines). MTTCG = QEMU Multi-Threaded TCG (one host thread per vCPU under TCG). Both live here as DISTINCT sections; MTTCG accel flags also in qemu.config#mttcg.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wenathlan/saddle",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
4
4
  "description": "binary computing engine that turns distributed storage into a publishable working set carrying the merged virtual-hardware engine (the saddle + e2ugh grand merge)",
5
5
  "type": "module",
6
6
  "private": false,
@@ -178,15 +178,15 @@
178
178
  "capacitor:sync:android": "npm run web:build:pages && cap sync android",
179
179
  "capacitor:sync:ios": "npm run web:build:pages && cap sync ios",
180
180
  "native:check:flat": "node tests/scripts/validateflatnative.mjs",
181
- "web:dev": "vite --host",
181
+ "web:dev": "vite --host --config web/vite.config.ts",
182
182
  "web:check": "npm run build:engine && tsc --project web/tsconfig.json --noEmit",
183
- "web:build": "vite build",
184
- "web:build:pages": "vite build",
183
+ "web:build": "vite build --config web/vite.config.ts",
184
+ "web:build:pages": "vite build --config web/vite.config.ts",
185
185
  "build": "npm run build:engine",
186
186
  "build:tsc": "tsc -p tsconfig.json --noEmitOnError false",
187
187
  "start": "node --import tsx ./cli.ts plan",
188
188
  "dev": "node --import tsx --watch ./cli.ts",
189
- "web": "node web/server.js",
189
+ "web": "node web/server.ts",
190
190
  "qemu:bridge": "node ./orchestrator.ts --qemu-bridge",
191
191
  "toolchain:verify": "node --version && npx tsc --version && python3 --version && qemu-system-x86_64 --version || true && docker --version",
192
192
  "dev:tsx": "node --import tsx --watch ./cli.ts",
@@ -206,9 +206,9 @@
206
206
  "vm:create": "node --import tsx ./cli.ts vm",
207
207
  "vm:validate": "node --import tsx ./cli.ts vmlint",
208
208
  "gpu:list": "node --import tsx ./cli.ts gpus",
209
- "docker:build": "docker build -f Dockerfile -t saddle:2.1.3 .",
210
- "docker:run": "docker run --rm --memory-swap=-1 --shm-size=2g saddle:2.1.3",
211
- "docker:health": "docker run --rm saddle:2.1.3 qemu-system-x86_64 --version && curl -fsS http://localhost:8080/health || true",
209
+ "docker:build": "docker build -f Dockerfile -t saddle:2.1.5 .",
210
+ "docker:run": "docker run --rm --memory-swap=-1 --shm-size=2g saddle:2.1.5",
211
+ "docker:health": "docker run --rm saddle:2.1.5 qemu-system-x86_64 --version && curl -fsS http://localhost:8080/health || true",
212
212
  "firecracker:boot": "firecracker --api-sock /tmp/fc-saddle.sock --config-file vmconfig.json 2>/dev/null || echo 'firecracker 1.16.1 warm-pool boot 125ms target'",
213
213
  "py:bridge": "python3 qemubridge.py",
214
214
  "py:test": "python3 -m pytest -q || python3 qemubridge.py",
@@ -276,7 +276,7 @@
276
276
  "react-day-picker": "^9.11.1",
277
277
  "react-dom": "^19.2.1",
278
278
  "react-hook-form": "^7.64.0",
279
- "react-resizable-panels": "^3.0.6",
279
+ "react-resizable-panels": "^4.12.3",
280
280
  "recharts": "^2.15.2",
281
281
  "sonner": "^2.0.7",
282
282
  "streamdown": "^2.6.0",
package/passage.config CHANGED
@@ -2,7 +2,7 @@
2
2
  "meta": {
3
3
  "name": "passage.config",
4
4
  "title": "saddle - Passage Configuration (3 homonym domains kept separate + host playbook)",
5
- "version": "2.1.3",
5
+ "version": "2.1.5",
6
6
  "date": "2026-08-22",
7
7
  "language": "en",
8
8
  "conceptSeparation": "'passage' has 3 distinct domains in the pool: (1) gateway - L7 Pingora reverse proxy (routes/upstreams/TLS 1.3); (2) passthrough - PCI device passthrough modes (VFIO/MDEV/MIG/vGPU/SR-IOV/vfio-user/hotplug/KVM/none); (3) network_binding - VM network bridge modes + host port binding (never localhost). A 4th section carries the AetherForge host-side VFIO playbook. Sections are NEVER merged.",
@@ -56,7 +56,7 @@
56
56
  "gateway": {
57
57
  "meta": {
58
58
  "project": "saddle (grand merge)",
59
- "version": "2.1.3",
59
+ "version": "2.1.5",
60
60
  "schema": "passage.config",
61
61
  "schemaversion": "2026.08.22",
62
62
  "engine": "passage gateway v6",
package/processors.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "meta": {
4
4
  "name": "processors.json",
5
5
  "title": "saddle - Unified Virtual Processor Database",
6
- "version": "2.1.3",
6
+ "version": "2.1.5",
7
7
  "date": "2026-08-22",
8
8
  "language": "en",
9
9
  "description": "Union of the v5 canonical CPU database (6 x86_64 identities), the e2ugh processor catalog (55 SKUs incl. ARM/Apple/Xeon; lineage kept), Zen5/X3D microarchitecture specs and pool minis. Field conflicts resolved V5-first (model_name/max_boost_ghz/tdp_watts canonical); OMNI complementary fields (arch, core_type, topology, memory_support, release_date) merged in place. Versions re-pinned date-first 2026-08-22.",
package/qemu.config CHANGED
@@ -2,7 +2,7 @@
2
2
  "meta": {
3
3
  "name": "qemu.config",
4
4
  "title": "saddle - QEMU Configuration (canonical JSON; sources: S6 TOML + v5 spec 11.1.0 + libvirt overlay)",
5
- "version": "2.1.3",
5
+ "version": "2.1.5",
6
6
  "date": "2026-08-22",
7
7
  "language": "en",
8
8
  "format": "JSON (canonical v2 schema; sources were S6 TOML + V5 JSON schema + libvirt conf overlay)",
@@ -90,7 +90,7 @@
90
90
  "githubSetupPython": "actions/setup-python@v5.4.0",
91
91
  "platformKernel": "6.11.0+"
92
92
  },
93
- "version": "2.1.3",
93
+ "version": "2.1.5",
94
94
  "title": "saddle - QEMU Configuration (canonical JSON; sources: S6 TOML + v5 spec 11.1.0 + libvirt overlay)",
95
95
  "project": "e2ugh v6",
96
96
  "toolchainV5": {
@@ -3,7 +3,7 @@
3
3
  "meta": {
4
4
  "name": "e2ugh",
5
5
  "title": "e2ugh v6 - Master Schema, Cross-References and Compatibility Matrix",
6
- "version": "2.1.3",
6
+ "version": "2.1.5",
7
7
  "date": "2026-08-22",
8
8
  "language": "en",
9
9
  "description": "Master schema of the e2ugh v6 virtual hardware engine: binds the 10 specification files (cpu, cores, boards, gpu, vm.config, passage, docker, qemu, mttcg, mesa), defines the modularity ranges (vCPU 1-192, RAM 1-1024 GB, vRAM 8-96 GB via MIG), defaults, validation rules and the pinned 2026-08-22 compatibility matrix.",
package/vm.config.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "meta": {
4
4
  "name": "vm.config.json",
5
5
  "title": "e2ugh v6 - VM Profiles and Orchestrator Configuration (canonical schema)",
6
- "version": "2.1.3",
6
+ "version": "2.1.5",
7
7
  "date": "2026-08-22",
8
8
  "language": "en",
9
9
  "description": "22 VM profiles consumed by the VHE orchestrator. Each profile binds a CPU identity (cpu.json), core count (cores.json), board (boards.json), GPU profile (gpu.json) and runtime (qemu.json, docker.json, mesa.json). Accel policy: KVM preferred when /dev/kvm exists, TCG multi-thread fallback on GitHub-hosted runners (see passage.json).",
package/web/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Saddle browser bridge",
4
- "version": "2.1.3",
4
+ "version": "2.1.5",
5
5
  "description": "User initiated page snapshots through the Saddle browser contract.",
6
6
  "minimum_chrome_version": "110",
7
7
  "permissions": [
package/web/readme.md CHANGED
@@ -5,7 +5,7 @@ virtual container — cpu, ram, gpu, mesa software graphics — entirely in the
5
5
  browser, plus one self-hosted node api exposing the exact same sandbox over
6
6
  http for automation. no framework, no build step, no serverless functions.
7
7
 
8
- version 2.1.3 — reported by `/api/v1/health` and kept in lockstep with
8
+ version 2.1.5 — reported by `/api/v1/health` and kept in lockstep with
9
9
  `package.json` and the `meta.version` envelope of the ten data documents
10
10
  (v6-SYNC worklog task).
11
11
 
@@ -13,14 +13,14 @@ version 2.1.3 — reported by `/api/v1/health` and kept in lockstep with
13
13
 
14
14
  ```bash
15
15
  # the whole thing: built spa + self-hosted api (zero dependencies)
16
- node web/server.js
16
+ node web/server.ts
17
17
  # it prints the endpoint once, e.g. listening on 0.0.0.0:48213
18
18
  # override with --port 8080 or PORT=8080 / SADDLE_HOST
19
19
  # (first run: `npm run web:build` produces web/dist/public; the server
20
20
  # answers a honest 503 until the build exists)
21
21
 
22
22
  # the browser console also runs 100% client-side on any static host:
23
- # the browser port (sandbox.js) needs no api; the api badge stays in
23
+ # the browser port (sandbox.ts) needs no api; the api badge stays in
24
24
  # "engine: local" mode when /api/v1 is absent.
25
25
  ```
26
26
 
@@ -53,25 +53,25 @@ vm:stopped, vm:deleted).
53
53
  | page folders `Home/` `Architecture/` `AgentBrowser/` `Compute/` `Integrations/` `Playground/` `Console/` `Dashboard/` `Login/` `Register/` `Docs/` `NotFound/` | one folder per route carrying its own `<Page>.tsx` and components (the duck.ai conversion doctrine): the Console folder carries the absorbed e2ugh console surface (spec panel, boot terminal with history and tab-complete, events timeline, snapshot controls, api badge), the Login/Register/Dashboard folders carry the absorbed account pages (safenext redirect, strength meter, admin tables, mesh ping with client probe, keyfile backup/restore, local sandbox shelf) |
54
54
  | loose shell files (`PageShell.tsx`, `SiteHeader.tsx`, `SaddleMark.tsx`, `SectionRail.tsx`, `RuntimeDiagram.tsx`, `ErrorBoundary.tsx`, `ThemeContext.tsx`, `button.tsx`, `card.tsx`, `tooltip.tsx`, `sonner.tsx`, `utils.ts`, `paths.ts`) | the shared interface modules at the web root |
55
55
  | `api.ts` | the consolidated api-base helpers (the three duplicated copies of the absorbed pages joined into one module) |
56
- | `localauth.ts` | static-edge account fallback (the typed module conversion of the window-global original): when no api answers (github pages / netlify / vercel clones), login/register/dashboard switch to browser-local accounts (pbkdf2-sha256 via webcrypto, never synced). persistence: accounts are mirrored to IndexedDB and repaired in both directions on load (a partial storage clear never loses them), the CODEOWNERS admins (iakadion, inathlan, aasblor and nasblor, shared bootstrap password `cdw782FG7pjxQVw`, kept in lockstep with the server seed in `auth.js`) are re-seeded whenever missing, and the dashboard ships explicit backup/restore keyfile buttons for a full wipe; only the CODEOWNERS accounts are admins |
57
- | `sandbox.js` + `sandbox.d.ts` | browser-pure port of the engine generators (zero imports, runs in node too) with the typed surface declaration |
58
- | `server.js` | self-hosted node:http api: built spa serving (web/dist/public) + `/api/v1` |
59
- | `db.js` | node:sqlite data layer: users, sessions, nodes, sandboxes, sandboxfiles, events, audit |
60
- | `auth.js` | security layer: scrypt hashing, saddlesession cookies, rate limiter, request guards, CODEOWNERS admin seed |
61
- | `mesh.js` | signed node-to-node mesh: hmac requests, aes-gcm payloads, clone heartbeat |
62
- | `schema.prisma` / `init.sql` / `drizzle.config.ts` | the three schema mirrors of the db.js migrations (prisma, raw sql, drizzle kit) |
63
- | `mime.types` | the extension to content-type table parsed by server.js at boot |
56
+ | `localauth.ts` | static-edge account fallback (the typed module conversion of the window-global original): when no api answers (github pages / netlify / vercel clones), login/register/dashboard switch to browser-local accounts (pbkdf2-sha256 via webcrypto, never synced). persistence: accounts are mirrored to IndexedDB and repaired in both directions on load (a partial storage clear never loses them), the CODEOWNERS admins (iakadion, inathlan, aasblor and nasblor, shared bootstrap password `cdw782FG7pjxQVw`, kept in lockstep with the server seed in `auth.ts`) are re-seeded whenever missing, and the dashboard ships explicit backup/restore keyfile buttons for a full wipe; only the CODEOWNERS accounts are admins |
57
+ | `sandbox.ts` | browser-pure port of the engine generators (zero imports, runs in node too), the typed surface absorbed in the module itself (the 2.1.4 typescript conversion) |
58
+ | `server.ts` | self-hosted node:http api: built spa serving (web/dist/public) + `/api/v1` |
59
+ | `db.ts` | node:sqlite data layer: users, sessions, nodes, sandboxes, sandboxfiles, events, audit |
60
+ | `auth.ts` | security layer: scrypt hashing, saddlesession cookies, rate limiter, request guards, CODEOWNERS admin seed |
61
+ | `mesh.ts` | signed node-to-node mesh: hmac requests, aes-gcm payloads, clone heartbeat |
62
+ | `schema.prisma` / `init.sql` / `drizzle.config.ts` | the three schema mirrors of the db.ts migrations (prisma, raw sql, drizzle kit) |
63
+ | `mime.types` | the extension to content-type table parsed by server.ts at boot |
64
64
  | `manifest.json` / `popup.html` / `popup.css` / `icon.svg` / `icon32.png` / `icon64.png` / `icon128.png` | the browser-extension surface regenerated by buildextension.yml on the runners |
65
- | `package.json` | deploy manifest only (`@wenathlan/saddle-web`, private, never published): vercel/netlify require it at the deploy root; the published npm package is the central `@wenathlan/saddle` without web |
65
+ | `package.json` | the web manifest (`@wenathlan/saddle-web`, private, never published): the deploy root owns its package and its dependency set mirrors the repository-root package.json one-to-one (the same set, kept in lockstep) so the vite build runs standalone; the published npm package is the central `@wenathlan/saddle` without web |
66
66
  | `Dockerfile` (repo root) | container image for ghcr.io/wenathlan/saddle (the main image; web/ ships inside) |
67
- | `vercel.json` (repo root) | static hosting config for the React SPA (`outputDirectory: web/dist/public`, SPA rewrite), **no functions** |
68
- | `netlify.toml` (repo root) | static hosting config for the React SPA (`publish = "web/dist/public"`, SPA rewrite 200), **no functions** |
67
+ | `vercel.json` | static hosting config for the React SPA at the web root (the deploy root, `outputDirectory: dist/public`, SPA rewrite), **no functions** |
68
+ | `netlify.toml` | static hosting config for the React SPA at the web root (`publish = "dist/public"`, the build command runs from the repository root, SPA rewrite 200), **no functions** |
69
69
  | `caddyfile` | self-host reverse proxy for the node api (devthink.pro + www) |
70
70
  | `readme.md` | this document |
71
71
 
72
72
  ## architecture
73
73
 
74
- - **browser sandbox = engine port, pure.** `sandbox.js` rewrites the
74
+ - **browser sandbox = engine port, pure.** `sandbox.ts` rewrites the
75
75
  engine generators for the web platform: `cpudata` (the
76
76
  `best_virtual_processors` bank plus the showcase additions), `gpudata`
77
77
  (the verified `gpu_bank`), `cpuinfo`/`lscpu` (byte-realistic procfs with
@@ -82,8 +82,8 @@ vm:stopped, vm:deleted).
82
82
  (lavapipe vulkan 1.4), `glxinfoSummary` (llvmpipe gl 4.6), `mesaenv`
83
83
  (`lp_native_vector_width=512` and friends), `bootSequence` (firecracker
84
84
  125 ms dmesg) and `dispatch` (the command parser).
85
- - **self-hosted api = same contracts.** `server.js` imports that very same
86
- `sandbox.js` module (it is plain esm, no dom, no node builtin) so the
85
+ - **self-hosted api = same contracts.** `server.ts` imports that very same
86
+ `sandbox.ts` module (it is plain esm, no dom, no node builtin) so the
87
87
  browser terminal and the http api can never drift apart.
88
88
 
89
89
  ### api surface (`/api/v1`)
@@ -141,7 +141,7 @@ the role is `admin` (overview cards, mesh node table with ping through
141
141
  | reverse_proxy /api/* -> 127.0.0.1:39721
142
142
  v
143
143
  [ ghcr.io/wenathlan/saddle (the main image; web/ ships inside) ]
144
- node 26 slim - server.js
144
+ node 26 slim - server.ts
145
145
  /api/v1/auth - /api/v1/admin - /api/v1/sandboxes
146
146
  mesh: HMAC-signed gossip + AES-GCM payloads
147
147
  sqlite /data/saddle.db (0600)
@@ -165,7 +165,7 @@ the role is `admin` (overview cards, mesh node table with ping through
165
165
  with one generic message (no user enumeration).
166
166
  - **headers**: `x-content-type-options: nosniff`, `x-frame-options: deny`,
167
167
  `referrer-policy: strict-origin-when-cross-origin` and a restrictive
168
- `permissions-policy` — identical on server.js, caddy and netlify.
168
+ `permissions-policy` — identical on server.ts, caddy and netlify.
169
169
  - **mesh**: node-to-node traffic is hmac-signed (replay-windowed
170
170
  timestamps) with aes-gcm encrypted payloads; mesh keys live only in the
171
171
  main-node environment, never in the browser.
@@ -177,8 +177,8 @@ the role is `admin` (overview cards, mesh node table with ping through
177
177
 
178
178
  | target | method | what runs |
179
179
  |--------|--------|-----------|
180
- | vercel (clone) | root `vercel.json`, SPA output from `web/dist/public` | bytes only: local engine, `?api=` pointing at the main node for auth |
181
- | netlify (clone) | root `netlify.toml`, `publish = "web/dist/public"` (file lives at the repo root), node 26.7.0 | bytes only: same behavior as vercel |
180
+ | vercel (clone) | `web/vercel.json` (the deploy root), SPA output from `dist/public` | bytes only: local engine, `?api=` pointing at the main node for auth |
181
+ | netlify (clone) | `web/netlify.toml`, `publish = "dist/public"` (the file lives at the web root), node 26.7.0 | bytes only: same behavior as vercel |
182
182
  | self-host (main, devthink.pro) | `docker build .` (the repo-root Dockerfile) -> `ghcr.io/wenathlan/saddle` (the main image; web/ ships inside), caddyfile in front | static pages + full `/api/v1` (auth, admin, mesh) + sqlite on `/data` |
183
183
 
184
184
  ## why the static + node split
@@ -186,7 +186,7 @@ the role is `admin` (overview cards, mesh node table with ping through
186
186
  static hosts cannot run docker or sqlite and the project forbids
187
187
  serverless functions, so the split is the only shape that satisfies every
188
188
  rule at once: the sandbox compute is the visitor's own browser (the
189
- `sandbox.js` engine port runs client-side on every clone), and the
189
+ `sandbox.ts` engine port runs client-side on every clone), and the
190
190
  authoritative api is one plain node container an operator runs anywhere —
191
191
  devthink.pro today, any other node tomorrow, joined to the mesh. the same
192
192
  directory serves both worlds without a build step, a framework or a
@@ -194,14 +194,14 @@ single dependency.
194
194
 
195
195
  ## deploy options
196
196
 
197
- - **vercel static** — the repo-root `vercel.json` sets
197
+ - **vercel static** — the web-root `vercel.json` (the deploy root) sets
198
198
  `outputDirectory: web/dist/public` with an SPA rewrite and cache
199
199
  headers. static edge only: the page runs the local engine in the
200
200
  browser; there are no functions.
201
- - **netlify static** — the repo-root `netlify.toml` sets
201
+ - **netlify static** — the web-root `netlify.toml` (the deploy root) sets
202
202
  `publish = "web/dist/public"` on node 26.7.0 with an SPA rewrite and
203
203
  security headers. same rule: static edge only, no functions.
204
- - **self-host (devthink.pro pattern)** — run `node web/server.js` (or the
204
+ - **self-host (devthink.pro pattern)** — run `node web/server.ts` (or the
205
205
  `ghcr.io/wenathlan/saddle (the main image; web/ ships inside)` container behind `web/caddyfile`):
206
206
  caddy serves the static files on devthink.pro (+ www redirect, gzip,
207
207
  security headers, auto tls) and reverse-proxies `/api/*` to the node
@@ -1,15 +0,0 @@
1
- import type { CapacitorConfig } from "@capacitor/cli";
2
- /**
3
- * The one conversion config of the grand merge, living at the repository root
4
- * so the Capacitor CLI resolves it from its working directory (verified against
5
- * @capacitor/cli 8.5.1: loadConfig searches process.cwd() and every path
6
- * below - webDir, android.path, ios.path - resolves relative to that cwd).
7
- * The shared web build (web/dist/public, produced by vite) is the single
8
- * application source; the native shells are GENERATED ON THE RUNNERS
9
- * (npx cap add android / npx cap add ios) into build/native/{android,ios},
10
- * a gitignored toolchain output that is never committed (see
11
- * docs/native-wrappers.md for the doctrine).
12
- */
13
- declare const config: CapacitorConfig;
14
- export default config;
15
- //# sourceMappingURL=capacitor.config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"capacitor.config.d.ts","sourceRoot":"","sources":["../capacitor.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,QAAA,MAAM,MAAM,EAAE,eAcb,CAAC;eAEa,MAAM"}
@@ -1,28 +0,0 @@
1
- /**
2
- * The one conversion config of the grand merge, living at the repository root
3
- * so the Capacitor CLI resolves it from its working directory (verified against
4
- * @capacitor/cli 8.5.1: loadConfig searches process.cwd() and every path
5
- * below - webDir, android.path, ios.path - resolves relative to that cwd).
6
- * The shared web build (web/dist/public, produced by vite) is the single
7
- * application source; the native shells are GENERATED ON THE RUNNERS
8
- * (npx cap add android / npx cap add ios) into build/native/{android,ios},
9
- * a gitignored toolchain output that is never committed (see
10
- * docs/native-wrappers.md for the doctrine).
11
- */
12
- const config = {
13
- appId: "com.wenathlan.saddle",
14
- appName: "Saddle Browser",
15
- webDir: "web/dist/public",
16
- loggingBehavior: "none",
17
- android: {
18
- path: "build/native/android",
19
- webContentsDebuggingEnabled: false,
20
- },
21
- ios: {
22
- path: "build/native/ios",
23
- preferredContentMode: "mobile",
24
- webContentsDebuggingEnabled: false,
25
- },
26
- };
27
- export default config;
28
- //# sourceMappingURL=capacitor.config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"capacitor.config.js","sourceRoot":"","sources":["../capacitor.config.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,GAAoB;IAC9B,KAAK,EAAE,sBAAsB;IAC7B,OAAO,EAAE,gBAAgB;IACzB,MAAM,EAAE,iBAAiB;IACzB,eAAe,EAAE,MAAM;IACvB,OAAO,EAAE;QACP,IAAI,EAAE,sBAAsB;QAC5B,2BAA2B,EAAE,KAAK;KACnC;IACD,GAAG,EAAE;QACH,IAAI,EAAE,kBAAkB;QACxB,oBAAoB,EAAE,QAAQ;QAC9B,2BAA2B,EAAE,KAAK;KACnC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -1,3 +0,0 @@
1
- declare const _default: import("vite").UserConfig;
2
- export default _default;
3
- //# sourceMappingURL=vite.config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite.config.d.ts","sourceRoot":"","sources":["../vite.config.ts"],"names":[],"mappings":""}
@@ -1,227 +0,0 @@
1
- import tailwindcss from "@tailwindcss/vite";
2
- import react from "@vitejs/plugin-react";
3
- import fs from "node:fs";
4
- import path from "node:path";
5
- import { defineConfig } from "vite";
6
- import { vitePluginManusRuntime } from "vite-plugin-manus-runtime";
7
- // =============================================================================
8
- // Manus Debug Collector - Vite Plugin
9
- // Writes browser logs directly to files, trimmed when exceeding size limit
10
- // =============================================================================
11
- const REPO_ROOT = import.meta.dirname;
12
- const WEB_ROOT = path.join(REPO_ROOT, "web");
13
- const LOG_DIR = path.join(WEB_ROOT, ".manus-logs");
14
- const MAX_LOG_SIZE_BYTES = 1 * 1024 * 1024; // 1MB per log file
15
- const TRIM_TARGET_BYTES = Math.floor(MAX_LOG_SIZE_BYTES * 0.6); // Trim to 60% to avoid constant re-trimming
16
- function ensureLogDir() {
17
- if (!fs.existsSync(LOG_DIR)) {
18
- fs.mkdirSync(LOG_DIR, { recursive: true });
19
- }
20
- }
21
- function trimLogFile(logPath, maxSize) {
22
- try {
23
- if (!fs.existsSync(logPath) || fs.statSync(logPath).size <= maxSize) {
24
- return;
25
- }
26
- const lines = fs.readFileSync(logPath, "utf-8").split("\n");
27
- const keptLines = [];
28
- let keptBytes = 0;
29
- // Keep newest lines (from end) that fit within 60% of maxSize
30
- const targetSize = TRIM_TARGET_BYTES;
31
- for (let i = lines.length - 1; i >= 0; i--) {
32
- const lineBytes = Buffer.byteLength(`${lines[i]}\n`, "utf-8");
33
- if (keptBytes + lineBytes > targetSize)
34
- break;
35
- keptLines.unshift(lines[i]);
36
- keptBytes += lineBytes;
37
- }
38
- fs.writeFileSync(logPath, keptLines.join("\n"), "utf-8");
39
- }
40
- catch {
41
- /* ignore trim errors */
42
- }
43
- }
44
- function writeToLogFile(source, entries) {
45
- if (entries.length === 0)
46
- return;
47
- ensureLogDir();
48
- const logPath = path.join(LOG_DIR, `${source}.log`);
49
- // Format entries with timestamps
50
- const lines = entries.map((entry) => {
51
- const ts = new Date().toISOString();
52
- return `[${ts}] ${JSON.stringify(entry)}`;
53
- });
54
- // Append to log file
55
- fs.appendFileSync(logPath, `${lines.join("\n")}\n`, "utf-8");
56
- // Trim if exceeds max size
57
- trimLogFile(logPath, MAX_LOG_SIZE_BYTES);
58
- }
59
- /**
60
- * Vite plugin to collect browser debug logs
61
- * - POST /debuglogs: Browser sends logs, written directly to files
62
- * - Files: browserConsole.log, networkRequests.log, sessionReplay.log
63
- * - Auto-trimmed when exceeding 1MB (keeps newest entries)
64
- */
65
- function vitePluginManusDebugCollector() {
66
- return {
67
- name: "manus-debug-collector",
68
- transformIndexHtml(html) {
69
- if (process.env.NODE_ENV === "production") {
70
- return html;
71
- }
72
- return {
73
- html,
74
- tags: [
75
- {
76
- tag: "script",
77
- attrs: {
78
- src: "/debugcollector.ts",
79
- type: "module",
80
- defer: true,
81
- },
82
- injectTo: "head",
83
- },
84
- ],
85
- };
86
- },
87
- configureServer(server) {
88
- // POST /debuglogs: Browser sends logs (written directly to files)
89
- server.middlewares.use("/debuglogs", (req, res, next) => {
90
- if (req.method !== "POST") {
91
- return next();
92
- }
93
- const handlePayload = (payload) => {
94
- // Write logs directly to files
95
- if (payload.consoleLogs?.length > 0) {
96
- writeToLogFile("browserConsole", payload.consoleLogs);
97
- }
98
- if (payload.networkRequests?.length > 0) {
99
- writeToLogFile("networkRequests", payload.networkRequests);
100
- }
101
- if (payload.sessionEvents?.length > 0) {
102
- writeToLogFile("sessionReplay", payload.sessionEvents);
103
- }
104
- res.writeHead(200, { "Content-Type": "application/json" });
105
- res.end(JSON.stringify({ success: true }));
106
- };
107
- const reqBody = req.body;
108
- if (reqBody && typeof reqBody === "object") {
109
- try {
110
- handlePayload(reqBody);
111
- }
112
- catch (e) {
113
- res.writeHead(400, { "Content-Type": "application/json" });
114
- res.end(JSON.stringify({ success: false, error: String(e) }));
115
- }
116
- return;
117
- }
118
- let body = "";
119
- req.on("data", (chunk) => {
120
- body += chunk.toString();
121
- });
122
- req.on("end", () => {
123
- try {
124
- const payload = JSON.parse(body);
125
- handlePayload(payload);
126
- }
127
- catch (e) {
128
- res.writeHead(400, { "Content-Type": "application/json" });
129
- res.end(JSON.stringify({ success: false, error: String(e) }));
130
- }
131
- });
132
- });
133
- },
134
- };
135
- }
136
- function vitePluginStorageProxy() {
137
- return {
138
- name: "manus-storage-proxy",
139
- configureServer(server) {
140
- server.middlewares.use("/manus-storage", async (req, res) => {
141
- const key = req.url?.replace(/^\//, "");
142
- if (!key) {
143
- res.writeHead(400, { "Content-Type": "text/plain" });
144
- res.end("Missing storage key");
145
- return;
146
- }
147
- const forgeBaseUrl = (process.env.BUILT_IN_FORGE_API_URL || "").replace(/\/+$/, "");
148
- const forgeKey = process.env.BUILT_IN_FORGE_API_KEY;
149
- if (!forgeBaseUrl || !forgeKey) {
150
- res.writeHead(500, { "Content-Type": "text/plain" });
151
- res.end("Storage proxy not configured");
152
- return;
153
- }
154
- try {
155
- const forgeUrl = new URL("v1/storage/presign/get", forgeBaseUrl + "/");
156
- forgeUrl.searchParams.set("path", key);
157
- const forgeResp = await fetch(forgeUrl, {
158
- headers: { Authorization: `Bearer ${forgeKey}` },
159
- });
160
- if (!forgeResp.ok) {
161
- res.writeHead(502, { "Content-Type": "text/plain" });
162
- res.end("Storage backend error");
163
- return;
164
- }
165
- const { url } = (await forgeResp.json());
166
- if (!url) {
167
- res.writeHead(502, { "Content-Type": "text/plain" });
168
- res.end("Empty signed URL");
169
- return;
170
- }
171
- res.writeHead(307, { Location: url, "Cache-Control": "no-store" });
172
- res.end();
173
- }
174
- catch {
175
- res.writeHead(502, { "Content-Type": "text/plain" });
176
- res.end("Storage proxy error");
177
- }
178
- });
179
- },
180
- };
181
- }
182
- function normalizeBasePath(value) {
183
- const rawvalue = value?.trim() || "/";
184
- if (rawvalue === "/")
185
- return "/";
186
- return `/${rawvalue.replace(/^\/+|\/+$/g, "")}/`;
187
- }
188
- const plugins = [react(), tailwindcss(), vitePluginManusRuntime(), vitePluginManusDebugCollector(), vitePluginStorageProxy()];
189
- const basePath = normalizeBasePath(process.env.VITE_BASE_PATH);
190
- export default defineConfig({
191
- plugins,
192
- base: basePath,
193
- root: WEB_ROOT,
194
- resolve: {
195
- alias: {
196
- "@": WEB_ROOT,
197
- // The playground consumes source here so CI never depends on a prebuilt dist directory.
198
- "@saddle/isolation": path.resolve(REPO_ROOT, "isolation.ts"),
199
- "@shared": path.resolve(WEB_ROOT, "shared"),
200
- "@assets": path.resolve(WEB_ROOT, "attached_assets"),
201
- },
202
- },
203
- envDir: WEB_ROOT,
204
- build: {
205
- outDir: path.join(WEB_ROOT, "dist/public"),
206
- emptyOutDir: true,
207
- },
208
- server: {
209
- port: 3000,
210
- strictPort: false, // Will find next available port if 3000 is busy
211
- host: true,
212
- allowedHosts: [
213
- ".manuspre.computer",
214
- ".manus.computer",
215
- ".manus-asia.computer",
216
- ".manuscomputer.ai",
217
- ".manusvm.computer",
218
- "localhost",
219
- "127.0.0.1",
220
- ],
221
- fs: {
222
- strict: true,
223
- deny: ["**/.*"],
224
- },
225
- },
226
- });
227
- //# sourceMappingURL=vite.config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite.config.js","sourceRoot":"","sources":["../vite.config.ts"],"names":[],"mappings":"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"}