@wenathlan/saddle 2.0.161 → 2.0.162
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 +171 -30
- package/README.md +1 -1
- package/modalityregistry.ts +17 -17
- package/package.json +78 -78
- package/sandbox.ts +15 -9
- package/tsconfig.json +6 -6
package/Dockerfile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# saddle 2.0.
|
|
1
|
+
# saddle 2.0.162 — THE ENGINE CONTAINER FILE
|
|
2
2
|
#
|
|
3
3
|
# THE FAMILY CONTAINER DOCTRINE, THE SADDLE SHAPE: one versioned container
|
|
4
4
|
# per engine, built like the site homes (argan, cadria) build theirs — a
|
|
@@ -16,14 +16,18 @@
|
|
|
16
16
|
# THE THREE VARIANT PROFILES (the saddle-exclusive law: the only app of
|
|
17
17
|
# the family that ships three) — select with the target flag:
|
|
18
18
|
#
|
|
19
|
-
# docker build --target max -t saddle:2.0.
|
|
20
|
-
# docker build --target balanced -t saddle:2.0.
|
|
21
|
-
# docker build --target lite -t saddle:2.0.
|
|
19
|
+
# docker build --target max -t saddle:2.0.162 .
|
|
20
|
+
# docker build --target balanced -t saddle:2.0.162-balanced .
|
|
21
|
+
# docker build --target lite -t saddle:2.0.162-lite .
|
|
22
22
|
#
|
|
23
23
|
# max — the full profile catalog: the epyc 9965 class, 192 vcpu,
|
|
24
24
|
# 384 threads, 1024 gib ram plan, the b200 gpu plan x8.
|
|
25
25
|
# balanced — the threadripper pro 9995wx class, 96 vcpu, 192 threads,
|
|
26
|
-
# 512 gib ram plan, the b200 gpu plan x2.
|
|
26
|
+
# 512 gib ram plan, the b200 gpu plan x2. THE DEFAULT
|
|
27
|
+
# TARGET: the plain `docker build -f saddle/Dockerfile .`
|
|
28
|
+
# with no --target answers the balanced stage (the last
|
|
29
|
+
# stage of the file) — the SADDLE_PROFILE lane's documented
|
|
30
|
+
# default — and the publish legs always name their target.
|
|
27
31
|
# lite — the ryzen 9950x3d class, 16 vcpu, 32 threads, 128 gib
|
|
28
32
|
# ram plan, the rtx 5090 gpu plan x1.
|
|
29
33
|
#
|
|
@@ -31,7 +35,31 @@
|
|
|
31
35
|
# assert), the catalog constants stay the publish matrix's single source,
|
|
32
36
|
# and every profile ships the same engine graph — the same ninety
|
|
33
37
|
# modalities, the same console, the same health surface; only the declared
|
|
34
|
-
# hardware plan differs.
|
|
38
|
+
# hardware plan differs. Each variant stage re-declares the six plan
|
|
39
|
+
# build-args with its own honest defaults and re-stamps the plan ENV, so a
|
|
40
|
+
# local `--target` leg answers its real hardware plan with no args passed
|
|
41
|
+
# (the publish legs pass the matrix constants per leg and override the
|
|
42
|
+
# defaults — one lane, two honest entries).
|
|
43
|
+
#
|
|
44
|
+
# THE ELEVEN-DEVICE BANK the profiles declare against (the exotic law's
|
|
45
|
+
# hardware vocabulary): the quickCatalog of saddle/virtualhardware.json
|
|
46
|
+
# carries exactly eleven virtual devices — seven cpu classes (epyc 9965,
|
|
47
|
+
# epyc 9755, threadripper 7995wx, ryzen 9950x3d, ryzen 9950x3d2, ryzen
|
|
48
|
+
# 9800x3d, xeon 6980p) and four gpu classes (rtx 5090, rtx pro 6000,
|
|
49
|
+
# b200, h100) — and the three profiles stamp their plan (the cpu class,
|
|
50
|
+
# the vcpu/thread counts, the ram plan, the gpu class and count) from
|
|
51
|
+
# that bank; every device stays virtual (the engine presents it, the
|
|
52
|
+
# visitor machine never lends its own).
|
|
53
|
+
#
|
|
54
|
+
# THE GUEST OS LANE the sandbox modalities answer (the owner's nickname
|
|
55
|
+
# law, saddle/docs/ninetymodalities.md): the spec vocabulary boots linux
|
|
56
|
+
# plus the nickname builds — marsh (marshmallow) resolves android,
|
|
57
|
+
# grapenios and grafene os resolve grapheneos, omashi resolves omarchy —
|
|
58
|
+
# and the owner's "v" names no guest os: it answers the languagev
|
|
59
|
+
# compiler seat of the ninety modalities. The container lane itself rides
|
|
60
|
+
# linux (the eleven-architecture standard below); the guest os vocabulary
|
|
61
|
+
# is the sandbox spec surface the console answers, never a host
|
|
62
|
+
# distribution this container installs.
|
|
35
63
|
#
|
|
36
64
|
# THE ELEVEN-ARCHITECTURE PLATFORM STANDARD (the pr15b law): every
|
|
37
65
|
# profile answers the eleven architectures the container standard names —
|
|
@@ -46,7 +74,13 @@
|
|
|
46
74
|
# loong64 and the wasm pair) answer the standard's honest coded absence
|
|
47
75
|
# (ARCH_IMAGE_ABSENT), never a pretended build leg — the same honesty
|
|
48
76
|
# law the containerarch table keeps for its own pinned base: a leg
|
|
49
|
-
# never claims a manifest the base does not carry.
|
|
77
|
+
# never claims a manifest the base does not carry. The base stage
|
|
78
|
+
# declares the TARGETPLATFORM/TARGETARCH automatic build-args (the
|
|
79
|
+
# devthink container's standard arch interface) and stamps the honesty
|
|
80
|
+
# law into the build log with its arch guard: a leg the base carries
|
|
81
|
+
# answers its leg line, a legacy builder without a platform axis answers
|
|
82
|
+
# its documented note, and anything else answers the coded refusal
|
|
83
|
+
# before a heavy step runs.
|
|
50
84
|
#
|
|
51
85
|
# THE CONTEXT LAW (the family context fix): this file COPYs from two
|
|
52
86
|
# trees (saddle/ and the engine-ownership sibling vault/), so every build
|
|
@@ -81,7 +115,7 @@ ARG NODE_BASE_DIGEST
|
|
|
81
115
|
# ===== stage: solbuild — the locked npm tree and the console spa =====
|
|
82
116
|
FROM --platform=$BUILDPLATFORM ${NODE_BASE_TAG}@sha256:${NODE_BASE_DIGEST} AS solbuild
|
|
83
117
|
|
|
84
|
-
ARG SADDLE_VERSION=2.0.
|
|
118
|
+
ARG SADDLE_VERSION=2.0.162
|
|
85
119
|
|
|
86
120
|
WORKDIR /app
|
|
87
121
|
|
|
@@ -109,7 +143,17 @@ RUN npm run web:build:pages \
|
|
|
109
143
|
# ===== stage: base — the hardened runtime floor every profile shares =====
|
|
110
144
|
FROM ${NODE_BASE_TAG}@sha256:${NODE_BASE_DIGEST} AS base
|
|
111
145
|
|
|
112
|
-
ARG SADDLE_VERSION=2.0.
|
|
146
|
+
ARG SADDLE_VERSION=2.0.162
|
|
147
|
+
# the revision stamp the devthink container carries (DEVTHINK_REVISION
|
|
148
|
+
# there): the publish legs pass the release sha at build time and the
|
|
149
|
+
# revision label below declares the default-unknown local shape.
|
|
150
|
+
ARG SADDLE_REVISION=unknown
|
|
151
|
+
# the automatic platform args (the devthink standard arch interface):
|
|
152
|
+
# the multi-arch node base resolves each leg's platform itself, and the
|
|
153
|
+
# arch guard below reads TARGETARCH to stamp the eleven-architecture
|
|
154
|
+
# law into the build log of every leg.
|
|
155
|
+
ARG TARGETPLATFORM
|
|
156
|
+
ARG TARGETARCH
|
|
113
157
|
ARG SADDLE_PROFILE=max
|
|
114
158
|
ARG VHE_PROFILE_CPU="epyc9965"
|
|
115
159
|
ARG VHE_PROFILE_VCPUS="192"
|
|
@@ -123,7 +167,8 @@ LABEL org.opencontainers.image.title="saddle" \
|
|
|
123
167
|
org.opencontainers.image.version="${SADDLE_VERSION}" \
|
|
124
168
|
org.opencontainers.image.licenses="GPL-3.0-only" \
|
|
125
169
|
org.opencontainers.image.source="https://github.com/wenathlan/devthink" \
|
|
126
|
-
org.opencontainers.image.documentation="https://github.com/wenathlan/devthink/tree/main/saddle"
|
|
170
|
+
org.opencontainers.image.documentation="https://github.com/wenathlan/devthink/tree/main/saddle" \
|
|
171
|
+
org.opencontainers.image.revision="${SADDLE_REVISION}"
|
|
127
172
|
|
|
128
173
|
WORKDIR /app
|
|
129
174
|
|
|
@@ -144,6 +189,24 @@ ENV NODE_ENV=production \
|
|
|
144
189
|
SADDLE_PROFILE_GPU=${VHE_PROFILE_GPU} \
|
|
145
190
|
SADDLE_PROFILE_GPUS=${VHE_PROFILE_GPUS}
|
|
146
191
|
|
|
192
|
+
# the arch-leg guard of the eleven-architecture standard: the pinned
|
|
193
|
+
# node base resolves the platform of every leg buildx names, and this
|
|
194
|
+
# echo layer stamps the honesty law into the build log — the four seats
|
|
195
|
+
# the base carries answer their leg line, the legacy builder (no
|
|
196
|
+
# platform axis) answers its documented note, and any other seat answers
|
|
197
|
+
# the coded refusal before the heavy steps below could run (buildx
|
|
198
|
+
# itself fails such a leg at base resolution first; the guard keeps the
|
|
199
|
+
# law loud on every builder).
|
|
200
|
+
RUN case "${TARGETARCH:-}" in \
|
|
201
|
+
amd64|arm64|ppc64le|s390x) \
|
|
202
|
+
echo "arch leg ${TARGETARCH} of ${TARGETPLATFORM:-<unresolved>}: one of the four seats the pinned node base carries of the eleven-architecture standard" ;; \
|
|
203
|
+
"") \
|
|
204
|
+
echo "arch leg unresolved: the legacy builder carries no platform axis; buildkit answers TARGETARCH per leg" ;; \
|
|
205
|
+
*) \
|
|
206
|
+
echo "the eleven-architecture standard answers the ${TARGETARCH} seat with the honest coded absence (ARCH_IMAGE_ABSENT): the pinned node base carries no such manifest" >&2; \
|
|
207
|
+
exit 1 ;; \
|
|
208
|
+
esac
|
|
209
|
+
|
|
147
210
|
COPY --from=solbuild /app/package.json /app/package-lock.json ./
|
|
148
211
|
RUN apt-get update \
|
|
149
212
|
&& apt-get upgrade -y \
|
|
@@ -196,45 +259,123 @@ RUN apt-get update \
|
|
|
196
259
|
# the solbuild stage lands it). with the graph closed, node
|
|
197
260
|
# webserver.ts starts clean; before the fix the container crashed at
|
|
198
261
|
# boot with module-not-found.
|
|
262
|
+
#
|
|
263
|
+
# The two lazy engine seats ride the same closed graph (the exotic law:
|
|
264
|
+
# the ninety modalities answer real runs inside the container, never the
|
|
265
|
+
# guarded absence): webserver.ts mounts the edge artifact vault through
|
|
266
|
+
# a first-use import of virtual.ts (the guarded loader degrades to null
|
|
267
|
+
# when the module is absent, so a container without it answers no
|
|
268
|
+
# artifact persistence), and edgelandes.ts lazily mounts virtual.ts for
|
|
269
|
+
# its virtual-file, s3 and persistence recipe seats plus tiers.ts for
|
|
270
|
+
# the kernel recipe seat — copying both keeps those seats live inside
|
|
271
|
+
# the container, and their import closures stay inside the set
|
|
272
|
+
# (virtual.ts pulls foundation.ts only; tiers.ts pulls node builtins
|
|
273
|
+
# only).
|
|
199
274
|
# run the console with: docker run saddle:<version>
|
|
200
|
-
COPY --from=solbuild /app/webserver.ts /app/db.ts /app/labels.ts /app/auth.ts /app/mesh.ts /app/sandbox.ts /app/modalityregistry.ts /app/edgeplane.ts /app/workloadlaw.ts /app/foundation.ts /app/edgelandes.ts /app/scriptlanes.ts /app/execution.ts /app/mime.types /app/init.sql /app/schema.prisma ./
|
|
275
|
+
COPY --from=solbuild /app/webserver.ts /app/db.ts /app/labels.ts /app/auth.ts /app/mesh.ts /app/sandbox.ts /app/modalityregistry.ts /app/edgeplane.ts /app/workloadlaw.ts /app/foundation.ts /app/edgelandes.ts /app/scriptlanes.ts /app/execution.ts /app/virtual.ts /app/tiers.ts /app/mime.types /app/init.sql /app/schema.prisma ./
|
|
201
276
|
# the label store of the console stack: labels.ts (pulled by db.ts)
|
|
202
277
|
# resolves ../vault/labelstore.ts at /vault - the same family context
|
|
203
278
|
# fix the solbuild stage applies.
|
|
204
279
|
COPY --from=solbuild /vault/labelstore.ts /vault/labelstore.ts
|
|
205
280
|
COPY --from=solbuild /out/spa ./
|
|
206
281
|
|
|
282
|
+
# the writable state home of the engine console (the vault engine
|
|
283
|
+
# container's /app/data pattern): db.ts resolves the sqlite store at
|
|
284
|
+
# import time (SADDLE_DB, else ./saddle.db under the working directory)
|
|
285
|
+
# and every directory the COPY chain staged stays root-owned, so the
|
|
286
|
+
# unprivileged node user needs a home it owns before the database file
|
|
287
|
+
# can open — without it the console crashed at boot on the sqlite
|
|
288
|
+
# cantopen refusal. An operator pins the persistent volume here; the
|
|
289
|
+
# engine creates the store on first boot.
|
|
290
|
+
RUN mkdir -p /app/data && chown -R node:node /app/data
|
|
291
|
+
|
|
207
292
|
USER node
|
|
208
293
|
|
|
209
294
|
# the console service doors: the webserver answers the engine api and the
|
|
210
295
|
# staged spa on the saddle port (the source-is-library law runs the .ts
|
|
211
|
-
# graph natively - node 26 strips the types, zero npm dependencies)
|
|
296
|
+
# graph natively - node 26 strips the types, zero npm dependencies), the
|
|
297
|
+
# port pin keeps the webserver's random-port fallback from ever
|
|
298
|
+
# answering, and the sqlite store opens under the writable state home
|
|
299
|
+
# above.
|
|
212
300
|
ENV SADDLE_PORT=8080 \
|
|
213
|
-
SADDLE_HOST=0.0.0.0
|
|
301
|
+
SADDLE_HOST=0.0.0.0 \
|
|
302
|
+
SADDLE_DB=/app/data/saddle.db
|
|
214
303
|
|
|
215
304
|
EXPOSE 8080
|
|
216
305
|
|
|
217
|
-
# the health probe rides the
|
|
218
|
-
# (
|
|
219
|
-
#
|
|
220
|
-
#
|
|
221
|
-
|
|
306
|
+
# the health probe rides the PUBLIC /api/v1/health route the webserver
|
|
307
|
+
# answers (the engine's own health surface: the ok flag, the version, the
|
|
308
|
+
# db healthcheck — never the spa shell the extensionless /health path
|
|
309
|
+
# serves, which would answer 200 html even with the engine sealed). The
|
|
310
|
+
# port follows SADDLE_PORT with the 8080 fallback (node fetch, zero wget
|
|
311
|
+
# dependency on the slim debian base; the callback spells function() — no
|
|
312
|
+
# arrow, no equal sign — so the dockle CIS-DI-0010 heuristic never reads
|
|
313
|
+
# a credential pair into the recorded healthcheck).
|
|
314
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 CMD ["node", "-e", "fetch('http://127.0.0.1:'+(process.env.SADDLE_PORT||8080)+'/api/v1/health').then(function(r){return r.json()}).then(function(j){if(!j.ok)process.exit(1)}).catch(function(){process.exit(1)})"]
|
|
222
315
|
|
|
223
316
|
ENTRYPOINT ["node", "webserver.ts"]
|
|
224
317
|
|
|
225
318
|
# ===== the variant profile targets (the saddle-exclusive three) =====
|
|
226
|
-
#
|
|
227
|
-
#
|
|
228
|
-
#
|
|
229
|
-
|
|
230
|
-
|
|
319
|
+
# Every variant stage re-declares the six plan build-args with its own
|
|
320
|
+
# honest defaults and re-stamps the plan ENV: a local `--target` leg
|
|
321
|
+
# answers its real hardware plan with no args passed (the pre-fix file
|
|
322
|
+
# stamped the max plan under every profile name when the caller passed
|
|
323
|
+
# no VHE_PROFILE_* args), and the publish legs pass the matrix constants
|
|
324
|
+
# per leg and override the defaults — the publish matrix stays the single
|
|
325
|
+
# source of the catalog either way.
|
|
231
326
|
|
|
232
|
-
#
|
|
233
|
-
|
|
234
|
-
|
|
327
|
+
# max — the full profile catalog: the epyc 9965 class, 192 vcpu, 384
|
|
328
|
+
# threads, 1024 gib ram, the b200 gpu plan x8 (the bare version tag the
|
|
329
|
+
# registry lane answers).
|
|
330
|
+
FROM base AS max
|
|
331
|
+
ARG VHE_PROFILE_CPU="epyc9965"
|
|
332
|
+
ARG VHE_PROFILE_VCPUS="192"
|
|
333
|
+
ARG VHE_PROFILE_THREADS="384"
|
|
334
|
+
ARG VHE_PROFILE_RAM_GB="1024"
|
|
335
|
+
ARG VHE_PROFILE_GPU="b200"
|
|
336
|
+
ARG VHE_PROFILE_GPUS="8"
|
|
337
|
+
ENV SADDLE_PROFILE=max \
|
|
338
|
+
SADDLE_PROFILE_CPU=${VHE_PROFILE_CPU} \
|
|
339
|
+
SADDLE_PROFILE_VCPUS=${VHE_PROFILE_VCPUS} \
|
|
340
|
+
SADDLE_PROFILE_THREADS=${VHE_PROFILE_THREADS} \
|
|
341
|
+
SADDLE_PROFILE_RAM_GB=${VHE_PROFILE_RAM_GB} \
|
|
342
|
+
SADDLE_PROFILE_GPU=${VHE_PROFILE_GPU} \
|
|
343
|
+
SADDLE_PROFILE_GPUS=${VHE_PROFILE_GPUS}
|
|
235
344
|
|
|
236
|
-
# lite — the ryzen class,
|
|
237
|
-
#
|
|
238
|
-
# lite, the lightest leg the family carries).
|
|
345
|
+
# lite — the ryzen 9950x3d class, 16 vcpu, 32 threads, 128 gib ram, the
|
|
346
|
+
# rtx 5090 gpu plan x1 (the -lite suffix tag the registry lane answers).
|
|
239
347
|
FROM base AS lite
|
|
240
|
-
|
|
348
|
+
ARG VHE_PROFILE_CPU="ryzen9950x3d"
|
|
349
|
+
ARG VHE_PROFILE_VCPUS="16"
|
|
350
|
+
ARG VHE_PROFILE_THREADS="32"
|
|
351
|
+
ARG VHE_PROFILE_RAM_GB="128"
|
|
352
|
+
ARG VHE_PROFILE_GPU="rtx5090"
|
|
353
|
+
ARG VHE_PROFILE_GPUS="1"
|
|
354
|
+
ENV SADDLE_PROFILE=lite \
|
|
355
|
+
SADDLE_PROFILE_CPU=${VHE_PROFILE_CPU} \
|
|
356
|
+
SADDLE_PROFILE_VCPUS=${VHE_PROFILE_VCPUS} \
|
|
357
|
+
SADDLE_PROFILE_THREADS=${VHE_PROFILE_THREADS} \
|
|
358
|
+
SADDLE_PROFILE_RAM_GB=${VHE_PROFILE_RAM_GB} \
|
|
359
|
+
SADDLE_PROFILE_GPU=${VHE_PROFILE_GPU} \
|
|
360
|
+
SADDLE_PROFILE_GPUS=${VHE_PROFILE_GPUS}
|
|
361
|
+
|
|
362
|
+
# balanced — the threadripper pro 9995wx class, 96 vcpu, 192 threads,
|
|
363
|
+
# 512 gib ram, the b200 gpu plan x2 (the -balanced suffix tag the
|
|
364
|
+
# registry lane answers). THE DEFAULT TARGET: the last stage of the
|
|
365
|
+
# file — the plain `docker build -f saddle/Dockerfile .` with no
|
|
366
|
+
# --target answers the balanced profile (the SADDLE_PROFILE lane's
|
|
367
|
+
# documented default).
|
|
368
|
+
FROM base AS balanced
|
|
369
|
+
ARG VHE_PROFILE_CPU="threadripperpro9995wx"
|
|
370
|
+
ARG VHE_PROFILE_VCPUS="96"
|
|
371
|
+
ARG VHE_PROFILE_THREADS="192"
|
|
372
|
+
ARG VHE_PROFILE_RAM_GB="512"
|
|
373
|
+
ARG VHE_PROFILE_GPU="b200"
|
|
374
|
+
ARG VHE_PROFILE_GPUS="2"
|
|
375
|
+
ENV SADDLE_PROFILE=balanced \
|
|
376
|
+
SADDLE_PROFILE_CPU=${VHE_PROFILE_CPU} \
|
|
377
|
+
SADDLE_PROFILE_VCPUS=${VHE_PROFILE_VCPUS} \
|
|
378
|
+
SADDLE_PROFILE_THREADS=${VHE_PROFILE_THREADS} \
|
|
379
|
+
SADDLE_PROFILE_RAM_GB=${VHE_PROFILE_RAM_GB} \
|
|
380
|
+
SADDLE_PROFILE_GPU=${VHE_PROFILE_GPU} \
|
|
381
|
+
SADDLE_PROFILE_GPUS=${VHE_PROFILE_GPUS}
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ domain modules land beside the saddle domains:
|
|
|
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
33
|
| `index.html`, `App.tsx`, `sol/` | the single SPA shell and the Sol theme (one tsx app with one stylesheet per theme) |
|
|
34
|
-
| `server.ts`, `sandbox.ts` | the zero-dependency self-hosted API of the 2.0.
|
|
34
|
+
| `server.ts`, `sandbox.ts` | the zero-dependency self-hosted API of the 2.0.162 grand-merge envelope (`node server.ts`; the api answers its version at `/api/v1/health`) and the browser-pure engine port |
|
|
35
35
|
| `vercel.json`, `netlify.toml` | the platform deploy adapters beside the surface they publish (the caddy ghost stays out of the tree) |
|
|
36
36
|
| `specs/*` package exports | processors, gpus, cores, boards and the qemu/mttg/passage/docker envelopes |
|
|
37
37
|
|
package/modalityregistry.ts
CHANGED
|
@@ -249,7 +249,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
249
249
|
label: "deno runtime",
|
|
250
250
|
family: "packages",
|
|
251
251
|
isolation: "process",
|
|
252
|
-
state: "
|
|
252
|
+
state: "planned",
|
|
253
253
|
drivers: ["deno"],
|
|
254
254
|
hardening: ["permission-map"],
|
|
255
255
|
boot: "hot",
|
|
@@ -305,7 +305,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
305
305
|
label: "v8 isolates",
|
|
306
306
|
family: "runner",
|
|
307
307
|
isolation: "process",
|
|
308
|
-
state: "
|
|
308
|
+
state: "planned",
|
|
309
309
|
drivers: ["v8"],
|
|
310
310
|
hardening: ["no-fs", "cpu-quota"],
|
|
311
311
|
boot: "hot",
|
|
@@ -351,7 +351,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
351
351
|
label: "rustc toolchain",
|
|
352
352
|
family: "language",
|
|
353
353
|
isolation: "process",
|
|
354
|
-
state: "
|
|
354
|
+
state: "planned",
|
|
355
355
|
drivers: ["rustc"],
|
|
356
356
|
hardening: ["crate-allowlist"],
|
|
357
357
|
boot: "hot",
|
|
@@ -365,7 +365,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
365
365
|
label: "cargo builds",
|
|
366
366
|
family: "language",
|
|
367
367
|
isolation: "process",
|
|
368
|
-
state: "
|
|
368
|
+
state: "planned",
|
|
369
369
|
drivers: ["cargo"],
|
|
370
370
|
hardening: ["crate-allowlist"],
|
|
371
371
|
boot: "hot",
|
|
@@ -379,7 +379,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
379
379
|
label: "v compiler",
|
|
380
380
|
family: "language",
|
|
381
381
|
isolation: "process",
|
|
382
|
-
state: "
|
|
382
|
+
state: "planned",
|
|
383
383
|
drivers: ["v"],
|
|
384
384
|
hardening: ["package-allowlist"],
|
|
385
385
|
boot: "hot",
|
|
@@ -407,7 +407,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
407
407
|
label: "dotnet runtime",
|
|
408
408
|
family: "language",
|
|
409
409
|
isolation: "process",
|
|
410
|
-
state: "
|
|
410
|
+
state: "planned",
|
|
411
411
|
drivers: ["dotnet"],
|
|
412
412
|
hardening: ["assembly-allowlist"],
|
|
413
413
|
boot: "warm",
|
|
@@ -435,7 +435,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
435
435
|
label: "php interpreter",
|
|
436
436
|
family: "language",
|
|
437
437
|
isolation: "process",
|
|
438
|
-
state: "
|
|
438
|
+
state: "planned",
|
|
439
439
|
drivers: ["php"],
|
|
440
440
|
hardening: ["ini-lockdown"],
|
|
441
441
|
boot: "hot",
|
|
@@ -449,7 +449,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
449
449
|
label: "lua interpreter",
|
|
450
450
|
family: "language",
|
|
451
451
|
isolation: "process",
|
|
452
|
-
state: "
|
|
452
|
+
state: "planned",
|
|
453
453
|
drivers: ["lua"],
|
|
454
454
|
hardening: ["sandbox-env"],
|
|
455
455
|
boot: "hot",
|
|
@@ -463,7 +463,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
463
463
|
label: "zig toolchain",
|
|
464
464
|
family: "language",
|
|
465
465
|
isolation: "process",
|
|
466
|
-
state: "
|
|
466
|
+
state: "planned",
|
|
467
467
|
drivers: ["zig"],
|
|
468
468
|
hardening: ["package-allowlist"],
|
|
469
469
|
boot: "hot",
|
|
@@ -477,7 +477,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
477
477
|
label: "nim compiler",
|
|
478
478
|
family: "language",
|
|
479
479
|
isolation: "process",
|
|
480
|
-
state: "
|
|
480
|
+
state: "planned",
|
|
481
481
|
drivers: ["nim"],
|
|
482
482
|
hardening: ["package-allowlist"],
|
|
483
483
|
boot: "hot",
|
|
@@ -536,7 +536,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
536
536
|
label: "wasi preview",
|
|
537
537
|
family: "wasm",
|
|
538
538
|
isolation: "process",
|
|
539
|
-
state: "
|
|
539
|
+
state: "planned",
|
|
540
540
|
drivers: ["wasmtime"],
|
|
541
541
|
hardening: ["capability-imports"],
|
|
542
542
|
boot: "hot",
|
|
@@ -933,7 +933,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
933
933
|
label: "git objects vfs",
|
|
934
934
|
family: "fs",
|
|
935
935
|
isolation: "process",
|
|
936
|
-
state: "
|
|
936
|
+
state: "planned",
|
|
937
937
|
drivers: ["git", "vfs"],
|
|
938
938
|
hardening: ["content-hash", "chunk-catalog"],
|
|
939
939
|
boot: "hot",
|
|
@@ -1024,7 +1024,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
1024
1024
|
label: "sqlite vault",
|
|
1025
1025
|
family: "storage",
|
|
1026
1026
|
isolation: "process",
|
|
1027
|
-
state: "
|
|
1027
|
+
state: "planned",
|
|
1028
1028
|
drivers: ["sqlite"],
|
|
1029
1029
|
hardening: ["file-quota"],
|
|
1030
1030
|
boot: "hot",
|
|
@@ -1124,7 +1124,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
1124
1124
|
label: "dns resolver",
|
|
1125
1125
|
family: "network",
|
|
1126
1126
|
isolation: "process",
|
|
1127
|
-
state: "
|
|
1127
|
+
state: "planned",
|
|
1128
1128
|
drivers: ["dns"],
|
|
1129
1129
|
hardening: ["resolver-allowlist"],
|
|
1130
1130
|
boot: "hot",
|
|
@@ -1138,7 +1138,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
1138
1138
|
label: "dns over https",
|
|
1139
1139
|
family: "network",
|
|
1140
1140
|
isolation: "process",
|
|
1141
|
-
state: "
|
|
1141
|
+
state: "planned",
|
|
1142
1142
|
drivers: ["doh"],
|
|
1143
1143
|
hardening: ["resolver-allowlist"],
|
|
1144
1144
|
boot: "hot",
|
|
@@ -1312,7 +1312,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
1312
1312
|
label: "make builds",
|
|
1313
1313
|
family: "build",
|
|
1314
1314
|
isolation: "process",
|
|
1315
|
-
state: "
|
|
1315
|
+
state: "planned",
|
|
1316
1316
|
drivers: ["make"],
|
|
1317
1317
|
hardening: ["recipe-allowlist"],
|
|
1318
1318
|
boot: "hot",
|
|
@@ -1354,7 +1354,7 @@ export const MODALITIES: readonly ModalityRecord[] = Object.freeze([
|
|
|
1354
1354
|
label: "ninja builds",
|
|
1355
1355
|
family: "build",
|
|
1356
1356
|
isolation: "process",
|
|
1357
|
-
state: "
|
|
1357
|
+
state: "planned",
|
|
1358
1358
|
drivers: ["ninja"],
|
|
1359
1359
|
hardening: ["recipe-allowlist"],
|
|
1360
1360
|
boot: "hot",
|
package/package.json
CHANGED
|
@@ -1,50 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wenathlan/saddle",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.162",
|
|
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
|
-
"type": "module",
|
|
6
|
-
"private": false,
|
|
7
|
-
"license": "GPL-3.0-only",
|
|
8
|
-
"author": "Wenathlan",
|
|
9
|
-
"sideEffects": false,
|
|
10
|
-
"main": "./index.ts",
|
|
11
|
-
"module": "./index.ts",
|
|
12
|
-
"browser": "./index.ts",
|
|
13
|
-
"types": "./index.ts",
|
|
14
|
-
"packageManager": "pnpm@12.3.4",
|
|
15
|
-
"publishConfig": {
|
|
16
|
-
"access": "public"
|
|
17
|
-
},
|
|
18
|
-
"overrides": {
|
|
19
|
-
"uuid": "^11.1.1",
|
|
20
|
-
"deepmerge-ts": "^8.0.0",
|
|
21
|
-
"esbuild": "^0.28.2",
|
|
22
|
-
"follow-redirects": "^1.16.2",
|
|
23
|
-
"minimatch": "^11.0.3",
|
|
24
|
-
"glob": "^14.0.3",
|
|
25
|
-
"mysql2": "^3.24.6",
|
|
26
|
-
"postcss-selector-parser": "^7.1.6",
|
|
27
|
-
"source-map-js": "1.2.2",
|
|
28
|
-
"proxy-addr": "2.0.8",
|
|
29
|
-
"body-parser": "^2.4.0",
|
|
30
|
-
"fast-uri": "^3.1.9",
|
|
31
|
-
"zod": "^4.6.7",
|
|
32
|
-
"undici": "^7.30.1",
|
|
33
|
-
"katex": "^0.18.2",
|
|
34
|
-
"shell-quote": "^1.11.0",
|
|
35
|
-
"xcode": {
|
|
36
|
-
"uuid": "11.1.1"
|
|
37
|
-
},
|
|
38
|
-
"@grpc/grpc-js": "1.14.5"
|
|
39
|
-
},
|
|
40
|
-
"repository": {
|
|
41
|
-
"type": "git",
|
|
42
|
-
"url": "https://github.com/wenathlan/devthink"
|
|
43
|
-
},
|
|
44
|
-
"bugs": {
|
|
45
|
-
"url": "https://github.com/wenathlan/saddle/issues"
|
|
46
|
-
},
|
|
47
|
-
"homepage": "https://github.com/wenathlan/saddle#readme",
|
|
48
5
|
"keywords": [
|
|
49
6
|
"distributed computing",
|
|
50
7
|
"virtual memory",
|
|
@@ -61,39 +18,20 @@
|
|
|
61
18
|
"mesa",
|
|
62
19
|
"ghcr"
|
|
63
20
|
],
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
"
|
|
67
|
-
"cargo": ">=1.85.0",
|
|
68
|
-
"chrome": "^16.0.912",
|
|
69
|
-
"cnpm": "^9.4.0",
|
|
70
|
-
"corepack": "^0.35.0",
|
|
71
|
-
"deno": "^2.9.5",
|
|
72
|
-
"dotnet": ">=8.0.0",
|
|
73
|
-
"ecmascript": "^5.0.0",
|
|
74
|
-
"firefox": ">=0.8.0",
|
|
75
|
-
"go": ">=1.24.0",
|
|
76
|
-
"iojs": "^1.0.0",
|
|
77
|
-
"java": ">=17",
|
|
78
|
-
"node": ">=26.13.0 <27",
|
|
79
|
-
"npm": "^12.2.1",
|
|
80
|
-
"pnpm": "^12.6.0",
|
|
81
|
-
"python": ">=3.11.0",
|
|
82
|
-
"rust": ">=1.85.0",
|
|
83
|
-
"teleport": ">=0.2.0",
|
|
84
|
-
"typescript": "^5.8.0",
|
|
85
|
-
"v": "^0.5.2",
|
|
86
|
-
"vscode": "^1.118.0",
|
|
87
|
-
"yarn": "^4.17.1"
|
|
88
|
-
},
|
|
89
|
-
"peerDependencies": {
|
|
90
|
-
"playwright": "^1.63.0"
|
|
21
|
+
"homepage": "https://github.com/wenathlan/saddle#readme",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/wenathlan/saddle/issues"
|
|
91
24
|
},
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
}
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/wenathlan/devthink"
|
|
96
28
|
},
|
|
29
|
+
"license": "GPL-3.0-only",
|
|
30
|
+
"author": "Wenathlan",
|
|
31
|
+
"type": "module",
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"main": "./index.ts",
|
|
34
|
+
"types": "./index.ts",
|
|
97
35
|
"bin": {
|
|
98
36
|
"saddle": "./cli.ts"
|
|
99
37
|
},
|
|
@@ -204,6 +142,34 @@
|
|
|
204
142
|
"tiers.ts",
|
|
205
143
|
"quantum.ts"
|
|
206
144
|
],
|
|
145
|
+
"engines": {
|
|
146
|
+
"bare": "^1.18.0",
|
|
147
|
+
"bun": "^1.4.4",
|
|
148
|
+
"cargo": ">=1.85.0",
|
|
149
|
+
"chrome": "^16.0.912",
|
|
150
|
+
"cnpm": "^9.4.0",
|
|
151
|
+
"corepack": "^0.35.0",
|
|
152
|
+
"deno": "^2.9.5",
|
|
153
|
+
"dotnet": ">=8.0.0",
|
|
154
|
+
"ecmascript": "^5.0.0",
|
|
155
|
+
"firefox": ">=0.8.0",
|
|
156
|
+
"go": ">=1.24.0",
|
|
157
|
+
"iojs": "^1.0.0",
|
|
158
|
+
"java": ">=17",
|
|
159
|
+
"node": ">=26.13.0 <27",
|
|
160
|
+
"npm": "^12.2.1",
|
|
161
|
+
"pnpm": "^12.6.0",
|
|
162
|
+
"python": ">=3.11.0",
|
|
163
|
+
"rust": ">=1.85.0",
|
|
164
|
+
"teleport": ">=0.2.0",
|
|
165
|
+
"typescript": "^5.8.0",
|
|
166
|
+
"v": "^0.5.2",
|
|
167
|
+
"vscode": "^1.118.0",
|
|
168
|
+
"yarn": "^4.17.1"
|
|
169
|
+
},
|
|
170
|
+
"peerDependencies": {
|
|
171
|
+
"playwright": "^1.63.0"
|
|
172
|
+
},
|
|
207
173
|
"scripts": {
|
|
208
174
|
"build:engine": "node scriptsbuildengine.ts",
|
|
209
175
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
@@ -248,9 +214,9 @@
|
|
|
248
214
|
"vm:create": "node --import tsx ./cli.ts vm",
|
|
249
215
|
"vm:validate": "node --import tsx ./cli.ts vmlint",
|
|
250
216
|
"gpu:list": "node --import tsx ./cli.ts gpus",
|
|
251
|
-
"docker:build": "docker build -f Dockerfile -t saddle:2.0.
|
|
252
|
-
"docker:run": "docker run --rm --memory-swap=-1 --shm-size=2g saddle:2.0.
|
|
253
|
-
"docker:health": "docker run --rm saddle:2.0.
|
|
217
|
+
"docker:build": "docker build -f Dockerfile -t saddle:2.0.162 .",
|
|
218
|
+
"docker:run": "docker run --rm --memory-swap=-1 --shm-size=2g saddle:2.0.162",
|
|
219
|
+
"docker:health": "docker run --rm saddle:2.0.162 qemu-system-x86_64 --version && curl -fsS http://localhost:8080/health || true",
|
|
254
220
|
"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'",
|
|
255
221
|
"py:bridge": "python3 qemubridge.py",
|
|
256
222
|
"py:test": "python3 -m pytest -q || python3 qemubridge.py",
|
|
@@ -386,6 +352,40 @@
|
|
|
386
352
|
"yaml": "^2.9.1",
|
|
387
353
|
"zod": "^4.6.7"
|
|
388
354
|
},
|
|
355
|
+
"overrides": {
|
|
356
|
+
"uuid": "^11.1.1",
|
|
357
|
+
"deepmerge-ts": "^8.0.0",
|
|
358
|
+
"esbuild": "^0.28.2",
|
|
359
|
+
"follow-redirects": "^1.16.2",
|
|
360
|
+
"minimatch": "^11.0.3",
|
|
361
|
+
"glob": "^14.0.3",
|
|
362
|
+
"mysql2": "^3.24.6",
|
|
363
|
+
"postcss-selector-parser": "^7.1.6",
|
|
364
|
+
"source-map-js": "1.2.2",
|
|
365
|
+
"proxy-addr": "2.0.8",
|
|
366
|
+
"body-parser": "^2.4.0",
|
|
367
|
+
"fast-uri": "^3.1.9",
|
|
368
|
+
"zod": "^4.6.7",
|
|
369
|
+
"undici": "^7.30.1",
|
|
370
|
+
"katex": "^0.18.2",
|
|
371
|
+
"shell-quote": "^1.11.0",
|
|
372
|
+
"xcode": {
|
|
373
|
+
"uuid": "11.1.1"
|
|
374
|
+
},
|
|
375
|
+
"@grpc/grpc-js": "1.14.5"
|
|
376
|
+
},
|
|
377
|
+
"publishConfig": {
|
|
378
|
+
"access": "public"
|
|
379
|
+
},
|
|
380
|
+
"packageManager": "pnpm@12.3.4",
|
|
381
|
+
"private": false,
|
|
382
|
+
"module": "./index.ts",
|
|
383
|
+
"browser": "./index.ts",
|
|
384
|
+
"peerDependenciesMeta": {
|
|
385
|
+
"playwright": {
|
|
386
|
+
"optional": true
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
389
|
"optionalDependencies": {
|
|
390
390
|
"commander": "^15.0.0",
|
|
391
391
|
"dockerode": "^5.0.1",
|
package/sandbox.ts
CHANGED
|
@@ -142,11 +142,14 @@ export type SandboxState = {
|
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
/** command result matching the api exec contract; clear is set by the
|
|
145
|
-
* clear command so the terminal can wipe the screen.
|
|
145
|
+
* clear command so the terminal can wipe the screen. code carries the
|
|
146
|
+
* machine refusal code of a structured honest answer — the sandbox never
|
|
147
|
+
* pretends a binary the image does not carry. */
|
|
146
148
|
export type DispatchResult = {
|
|
147
149
|
output: string;
|
|
148
150
|
exitCode: number;
|
|
149
151
|
clear?: boolean;
|
|
152
|
+
code?: string;
|
|
150
153
|
};
|
|
151
154
|
|
|
152
155
|
/** optional exec context provided by the api host. */
|
|
@@ -1452,8 +1455,8 @@ function helpText(): string {
|
|
|
1452
1455
|
['uname -a', 'kernel and architecture line'],
|
|
1453
1456
|
['ls /etc/virtual', 'virtual hardware definition files'],
|
|
1454
1457
|
['env', 'mesa llvmpipe environment variables'],
|
|
1455
|
-
['docker --version', '
|
|
1456
|
-
['qemu-system-x86_64 --version', '
|
|
1458
|
+
['docker --version', 'honest refusal: the binary is absent from the sandbox image'],
|
|
1459
|
+
['qemu-system-x86_64 --version', 'honest refusal: the binary is absent from the sandbox image'],
|
|
1457
1460
|
['uptime', 'sandbox uptime and load average'],
|
|
1458
1461
|
['whoami', 'current user'],
|
|
1459
1462
|
['neofetch', 'saddle ascii logo and sandbox specs'],
|
|
@@ -1826,15 +1829,18 @@ export function dispatch(
|
|
|
1826
1829
|
}
|
|
1827
1830
|
case 'env':
|
|
1828
1831
|
return { output: envText(state), exitCode: 0 };
|
|
1832
|
+
/* the honesty law: the sandbox image carries no container daemon
|
|
1833
|
+
* and no emulator binary, so the shell never fakes a version
|
|
1834
|
+
* banner — the answer is the structured honest refusal, the
|
|
1835
|
+
* machine code rides the result and the message names the absence
|
|
1836
|
+
* and the real surface (the host container and qemu runtimes ride
|
|
1837
|
+
* the edge plane lanes, never a pretended guest binary). */
|
|
1829
1838
|
case 'docker':
|
|
1830
|
-
return { output: 'Docker version 29.7.2, build 5ea4c1f', exitCode: 0 };
|
|
1831
1839
|
case 'qemu-system-x86_64':
|
|
1832
1840
|
return {
|
|
1833
|
-
output:
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
].join('\n'),
|
|
1837
|
-
exitCode: 0,
|
|
1841
|
+
output: `bash: ${head}: the ${head} binary is absent from this sandbox image (SANDBOX_IMAGE_ABSENT) — the sandbox mounts no container daemon and no emulator, the engine drives the host container and qemu lanes through the edge plane`,
|
|
1842
|
+
exitCode: 127,
|
|
1843
|
+
code: 'SANDBOX_IMAGE_ABSENT',
|
|
1838
1844
|
};
|
|
1839
1845
|
case 'uptime':
|
|
1840
1846
|
return { output: uptimeLine(state), exitCode: 0 };
|
package/tsconfig.json
CHANGED
|
@@ -8,20 +8,20 @@
|
|
|
8
8
|
// one project keeps covering the Sol surface.
|
|
9
9
|
{
|
|
10
10
|
"compilerOptions": {
|
|
11
|
-
"module": "NodeNext",
|
|
12
|
-
"moduleResolution": "NodeNext",
|
|
13
11
|
"target": "ES2024",
|
|
14
|
-
"lib": ["ES2024", "dom", "dom.iterable"],
|
|
15
|
-
"jsx": "react-jsx",
|
|
16
12
|
"noEmit": true,
|
|
17
|
-
"
|
|
13
|
+
"module": "NodeNext",
|
|
18
14
|
"strict": false,
|
|
19
15
|
"noCheck": true,
|
|
16
|
+
"lib": ["es2024", "dom", "dom.iterable"],
|
|
17
|
+
"jsx": "react-jsx",
|
|
20
18
|
"esModuleInterop": true,
|
|
19
|
+
"allowSyntheticDefaultImports": true,
|
|
21
20
|
"skipLibCheck": true,
|
|
21
|
+
"allowImportingTsExtensions": true,
|
|
22
22
|
"isolatedModules": true,
|
|
23
|
-
"allowSyntheticDefaultImports": true,
|
|
24
23
|
"forceConsistentCasingInFileNames": true,
|
|
24
|
+
"moduleResolution": "NodeNext",
|
|
25
25
|
"types": ["node", "vite/client"],
|
|
26
26
|
"paths": {
|
|
27
27
|
"@/*": ["./sol/*", "./*"],
|