@wenathlan/saddle 2.0.153 → 2.0.155

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.
Files changed (307) hide show
  1. package/Dockerfile +139 -55
  2. package/README.md +58 -59
  3. package/browser.ts +482 -0
  4. package/cli.ts +274 -0
  5. package/distribution.ts +731 -0
  6. package/docker.config +29 -8
  7. package/docs/artifactavailability.md +2 -2
  8. package/docs/browser.md +18 -1
  9. package/docs/{containerplatforms.2.1.0.md → containerplatforms210.md} +1 -1
  10. package/docs/{documentmap.1.8.12.md → documentmap1812.md} +1 -1
  11. package/docs/extension.md +13 -2
  12. package/docs/libraryapi.md +1 -1
  13. package/docs/{ninety.modalities.md → ninetymodalities.md} +87 -4
  14. package/docs/{planning.ninety.md → planningninety.md} +6 -6
  15. package/docs/{releasenotes.1.8.13.md → releasenotes1813.md} +2 -2
  16. package/docs/{releasenotes.1.8.14.md → releasenotes1814.md} +1 -1
  17. package/docs/{repo.synthesis.1.8.16.md → reposynthesis1816.md} +1 -1
  18. package/docs/todo.md +2 -2
  19. package/docs/{todo.1.8.15.md → todo1815.md} +1 -1
  20. package/docs/{todo.1.8.16.md → todo1816.md} +5 -5
  21. package/execution.ts +677 -0
  22. package/foundation.ts +314 -0
  23. package/index.ts +35 -27
  24. package/isolation.ts +84 -0
  25. package/modes.ts +170 -0
  26. package/mttg.config +1 -1
  27. package/orchestrator.ts +49 -15
  28. package/package.json +90 -75
  29. package/qemu.config +2 -2
  30. package/sandbox.ts +2094 -0
  31. package/scheduler.ts +1 -1
  32. package/server.ts +52 -0
  33. package/tsconfig.json +11 -12
  34. package/virtual.ts +1105 -0
  35. package/virtualgpu.ts +1 -1
  36. package/virtualization.ts +1 -1
  37. package/workloadlaw.ts +293 -0
  38. package/dist/App.d.ts +0 -5
  39. package/dist/App.js +0 -52
  40. package/dist/Sol/Sol.d.ts +0 -3
  41. package/dist/Sol/Sol.js +0 -46
  42. package/dist/Sol/agentbrowser/agentbrowser.d.ts +0 -9
  43. package/dist/Sol/agentbrowser/agentbrowser.js +0 -121
  44. package/dist/Sol/architecture/architecture.d.ts +0 -9
  45. package/dist/Sol/architecture/architecture.js +0 -93
  46. package/dist/Sol/compute/compute.d.ts +0 -9
  47. package/dist/Sol/compute/compute.js +0 -22
  48. package/dist/Sol/console/console.d.ts +0 -15
  49. package/dist/Sol/console/console.js +0 -292
  50. package/dist/Sol/dashboard/dashboard.d.ts +0 -10
  51. package/dist/Sol/dashboard/dashboard.js +0 -181
  52. package/dist/Sol/docs/docs.d.ts +0 -9
  53. package/dist/Sol/docs/docs.js +0 -28
  54. package/dist/Sol/home/home.d.ts +0 -35
  55. package/dist/Sol/home/home.js +0 -239
  56. package/dist/Sol/integrations/integrations.d.ts +0 -9
  57. package/dist/Sol/integrations/integrations.js +0 -83
  58. package/dist/Sol/intro/intro.d.ts +0 -7
  59. package/dist/Sol/intro/intro.js +0 -102
  60. package/dist/Sol/login/login.d.ts +0 -16
  61. package/dist/Sol/login/login.js +0 -49
  62. package/dist/Sol/notfound/notfound.d.ts +0 -9
  63. package/dist/Sol/notfound/notfound.js +0 -15
  64. package/dist/Sol/onboarding/onboarding.d.ts +0 -25
  65. package/dist/Sol/onboarding/onboarding.js +0 -60
  66. package/dist/Sol/playground/playground.d.ts +0 -9
  67. package/dist/Sol/playground/playground.js +0 -127
  68. package/dist/Sol/register/register.d.ts +0 -16
  69. package/dist/Sol/register/register.js +0 -193
  70. package/dist/Sol/shell/Shell.d.ts +0 -124
  71. package/dist/Sol/shell/Shell.js +0 -335
  72. package/dist/Sol/wingets/ComputeBootladder.d.ts +0 -6
  73. package/dist/Sol/wingets/ComputeBootladder.js +0 -71
  74. package/dist/Sol/wingets/ComputeModalitycatalog.d.ts +0 -7
  75. package/dist/Sol/wingets/ComputeModalitycatalog.js +0 -71
  76. package/dist/Sol/wingets/ConsoleApibadge.d.ts +0 -7
  77. package/dist/Sol/wingets/ConsoleApibadge.js +0 -5
  78. package/dist/Sol/wingets/ConsoleEdgelaw.d.ts +0 -6
  79. package/dist/Sol/wingets/ConsoleEdgelaw.js +0 -36
  80. package/dist/Sol/wingets/ConsoleEventstimeline.d.ts +0 -19
  81. package/dist/Sol/wingets/ConsoleEventstimeline.js +0 -12
  82. package/dist/Sol/wingets/ConsoleSnapshotcontrols.d.ts +0 -8
  83. package/dist/Sol/wingets/ConsoleSnapshotcontrols.js +0 -8
  84. package/dist/Sol/wingets/ConsoleSpecpanel.d.ts +0 -21
  85. package/dist/Sol/wingets/ConsoleSpecpanel.js +0 -75
  86. package/dist/Sol/wingets/ConsoleTerminal.d.ts +0 -22
  87. package/dist/Sol/wingets/ConsoleTerminal.js +0 -77
  88. package/dist/Sol/wingets/DashboardAccountpanel.d.ts +0 -18
  89. package/dist/Sol/wingets/DashboardAccountpanel.js +0 -65
  90. package/dist/Sol/wingets/DashboardAdminpanel.d.ts +0 -6
  91. package/dist/Sol/wingets/DashboardAdminpanel.js +0 -90
  92. package/dist/Sol/wingets/DashboardAuditlog.d.ts +0 -8
  93. package/dist/Sol/wingets/DashboardAuditlog.js +0 -50
  94. package/dist/Sol/wingets/DashboardCreatesandboxform.d.ts +0 -10
  95. package/dist/Sol/wingets/DashboardCreatesandboxform.js +0 -71
  96. package/dist/Sol/wingets/DashboardEventstimeline.d.ts +0 -8
  97. package/dist/Sol/wingets/DashboardEventstimeline.js +0 -83
  98. package/dist/Sol/wingets/DashboardGlobalsandboxestable.d.ts +0 -8
  99. package/dist/Sol/wingets/DashboardGlobalsandboxestable.js +0 -57
  100. package/dist/Sol/wingets/DashboardMeshnodestable.d.ts +0 -8
  101. package/dist/Sol/wingets/DashboardMeshnodestable.js +0 -103
  102. package/dist/Sol/wingets/DashboardSandboxlist.d.ts +0 -10
  103. package/dist/Sol/wingets/DashboardSandboxlist.js +0 -163
  104. package/dist/Sol/wingets/DashboardUserstable.d.ts +0 -8
  105. package/dist/Sol/wingets/DashboardUserstable.js +0 -78
  106. package/dist/Sol/wingets/HomeEntrygate.d.ts +0 -23
  107. package/dist/Sol/wingets/HomeEntrygate.js +0 -73
  108. package/dist/Sol/wingets/HomeMetricstrip.d.ts +0 -9
  109. package/dist/Sol/wingets/HomeMetricstrip.js +0 -4
  110. package/dist/Sol/wingets/HomeRuntimediagram.d.ts +0 -1
  111. package/dist/Sol/wingets/HomeRuntimediagram.js +0 -22
  112. package/dist/Sol/wingets/LoginForm.d.ts +0 -19
  113. package/dist/Sol/wingets/LoginForm.js +0 -141
  114. package/dist/Sol/wingets/RegisterPasswordconfirm.d.ts +0 -13
  115. package/dist/Sol/wingets/RegisterPasswordconfirm.js +0 -16
  116. package/dist/Sol/wingets/RegisterPasswordmeter.d.ts +0 -19
  117. package/dist/Sol/wingets/RegisterPasswordmeter.js +0 -65
  118. package/dist/Sol/wingets/RegisterUsernamerules.d.ts +0 -11
  119. package/dist/Sol/wingets/RegisterUsernamerules.js +0 -16
  120. package/dist/Sol/wingets/index.d.ts +0 -39
  121. package/dist/Sol/wingets/index.js +0 -39
  122. package/dist/alternatives.d.ts +0 -508
  123. package/dist/alternatives.js +0 -950
  124. package/dist/api.d.ts +0 -154
  125. package/dist/api.js +0 -174
  126. package/dist/auth.d.ts +0 -268
  127. package/dist/auth.js +0 -476
  128. package/dist/automation.d.ts +0 -425
  129. package/dist/automation.js +0 -566
  130. package/dist/browser.d.ts +0 -561
  131. package/dist/browser.js +0 -1058
  132. package/dist/capacitor.config.d.ts +0 -45
  133. package/dist/capacitor.config.js +0 -48
  134. package/dist/catalog.d.ts +0 -43
  135. package/dist/catalog.js +0 -44
  136. package/dist/cli.d.ts +0 -16
  137. package/dist/cli.js +0 -168
  138. package/dist/communication.d.ts +0 -181
  139. package/dist/communication.js +0 -376
  140. package/dist/compute.d.ts +0 -1160
  141. package/dist/compute.js +0 -2272
  142. package/dist/dashboardlib.d.ts +0 -58
  143. package/dist/dashboardlib.js +0 -161
  144. package/dist/db.d.ts +0 -569
  145. package/dist/db.js +0 -1080
  146. package/dist/distribution.d.ts +0 -528
  147. package/dist/distribution.js +0 -810
  148. package/dist/drizzle.config.d.ts +0 -20
  149. package/dist/drizzle.config.js +0 -18
  150. package/dist/edgelandes.d.ts +0 -70
  151. package/dist/edgelandes.host.d.ts +0 -26
  152. package/dist/edgelandes.host.js +0 -1089
  153. package/dist/edgelandes.inproc.d.ts +0 -27
  154. package/dist/edgelandes.inproc.js +0 -952
  155. package/dist/edgelandes.js +0 -1133
  156. package/dist/edgelandes.ninety.d.ts +0 -31
  157. package/dist/edgelandes.ninety.js +0 -174
  158. package/dist/edgelandes.virtual.d.ts +0 -25
  159. package/dist/edgelandes.virtual.js +0 -629
  160. package/dist/edgeplane.d.ts +0 -114
  161. package/dist/edgeplane.js +0 -305
  162. package/dist/examplelocaljob.d.ts +0 -1
  163. package/dist/examplelocaljob.js +0 -14
  164. package/dist/execution.d.ts +0 -529
  165. package/dist/execution.js +0 -760
  166. package/dist/family.d.ts +0 -16
  167. package/dist/family.js +0 -42
  168. package/dist/familyurl.d.ts +0 -21
  169. package/dist/familyurl.js +0 -24
  170. package/dist/format.d.ts +0 -18
  171. package/dist/format.js +0 -59
  172. package/dist/foundation.d.ts +0 -172
  173. package/dist/foundation.js +0 -312
  174. package/dist/index.d.ts +0 -735
  175. package/dist/index.js +0 -1020
  176. package/dist/integration.d.ts +0 -235
  177. package/dist/integration.js +0 -228
  178. package/dist/intelligence.d.ts +0 -93
  179. package/dist/intelligence.js +0 -144
  180. package/dist/isolation.d.ts +0 -128
  181. package/dist/isolation.js +0 -95
  182. package/dist/labels.d.ts +0 -665
  183. package/dist/labels.js +0 -751
  184. package/dist/localauth.d.ts +0 -127
  185. package/dist/localauth.js +0 -413
  186. package/dist/media.d.ts +0 -343
  187. package/dist/media.js +0 -985
  188. package/dist/mesh.d.ts +0 -177
  189. package/dist/mesh.js +0 -468
  190. package/dist/modalityregistry.d.ts +0 -109
  191. package/dist/modalityregistry.js +0 -1386
  192. package/dist/modes.d.ts +0 -358
  193. package/dist/modes.js +0 -133
  194. package/dist/onboardingstate.d.ts +0 -79
  195. package/dist/onboardingstate.js +0 -282
  196. package/dist/orchestrator.d.ts +0 -1338
  197. package/dist/orchestrator.js +0 -4310
  198. package/dist/packager/targetcli.js +0 -4
  199. package/dist/paths.d.ts +0 -2
  200. package/dist/paths.js +0 -14
  201. package/dist/performance.d.ts +0 -415
  202. package/dist/performance.js +0 -826
  203. package/dist/quantum.d.ts +0 -809
  204. package/dist/quantum.js +0 -2072
  205. package/dist/render.d.ts +0 -380
  206. package/dist/render.js +0 -1072
  207. package/dist/runall.d.ts +0 -2
  208. package/dist/runall.js +0 -39
  209. package/dist/runtimeprobe.d.ts +0 -4
  210. package/dist/runtimeprobe.js +0 -8
  211. package/dist/sandbox.d.ts +0 -355
  212. package/dist/sandbox.js +0 -1721
  213. package/dist/sandboxenvprofile.d.ts +0 -29
  214. package/dist/sandboxenvprofile.js +0 -89
  215. package/dist/sandboxprofile.d.ts +0 -137
  216. package/dist/sandboxprofile.js +0 -241
  217. package/dist/sandboxqueue.d.ts +0 -108
  218. package/dist/sandboxqueue.js +0 -201
  219. package/dist/sandboxquota.d.ts +0 -121
  220. package/dist/sandboxquota.js +0 -236
  221. package/dist/scheduler.d.ts +0 -595
  222. package/dist/scheduler.js +0 -1258
  223. package/dist/scriptlanes.d.ts +0 -182
  224. package/dist/scriptlanes.js +0 -660
  225. package/dist/scripts.buildengine.d.ts +0 -1
  226. package/dist/scripts.buildengine.js +0 -39
  227. package/dist/scripts.securitygate.d.ts +0 -1
  228. package/dist/scripts.securitygate.js +0 -68
  229. package/dist/scripts.validateflatnative.d.ts +0 -1
  230. package/dist/scripts.validateflatnative.js +0 -72
  231. package/dist/security.d.ts +0 -500
  232. package/dist/security.js +0 -1169
  233. package/dist/seedcatalog.d.ts +0 -13
  234. package/dist/seedcatalog.js +0 -46
  235. package/dist/server.d.ts +0 -20
  236. package/dist/server.js +0 -53
  237. package/dist/speccatalog.d.ts +0 -31
  238. package/dist/speccatalog.js +0 -163
  239. package/dist/tiers.d.ts +0 -1001
  240. package/dist/tiers.js +0 -2169
  241. package/dist/utils.d.ts +0 -2
  242. package/dist/utils.js +0 -5
  243. package/dist/vaulthandoff.d.ts +0 -141
  244. package/dist/vaulthandoff.js +0 -444
  245. package/dist/virtual.d.ts +0 -640
  246. package/dist/virtual.js +0 -1284
  247. package/dist/virtualcpu.d.ts +0 -315
  248. package/dist/virtualcpu.js +0 -1180
  249. package/dist/virtualgpu.d.ts +0 -344
  250. package/dist/virtualgpu.js +0 -1000
  251. package/dist/virtualization.d.ts +0 -606
  252. package/dist/virtualization.js +0 -1186
  253. package/dist/virtualmemory.d.ts +0 -817
  254. package/dist/virtualmemory.js +0 -1795
  255. package/dist/vite.config.d.ts +0 -3
  256. package/dist/vite.config.js +0 -43
  257. package/dist/vitest.config.d.ts +0 -2
  258. package/dist/vitest.config.js +0 -25
  259. package/dist/webserver.d.ts +0 -166
  260. package/dist/webserver.js +0 -2226
  261. package/dist/workloadlaw.d.ts +0 -133
  262. package/dist/workloadlaw.js +0 -193
  263. package/manifest.json +0 -20
  264. package/media.ts +0 -1337
  265. /package/docs/{architecture.1.8.19.md → architecture1819.md} +0 -0
  266. /package/docs/{architecture.1.8.19.mmd → architecture1819.mmd} +0 -0
  267. /package/docs/{artifactresearch.1.8.9.md → artifactresearch189.md} +0 -0
  268. /package/docs/{batches.1816.to.1820.md → batches1816to1820.md} +0 -0
  269. /package/docs/{brancharchive.2026.08.18.md → brancharchive20260818.md} +0 -0
  270. /package/docs/{containerplatforms.1.8.17.md → containerplatforms1817.md} +0 -0
  271. /package/docs/{e2ugh.engine.md → e2ughengine.md} +0 -0
  272. /package/docs/{flatbuildresearch.1.8.11.md → flatbuildresearch1811.md} +0 -0
  273. /package/docs/{licenseaudit.1.8.12.md → licenseaudit1812.md} +0 -0
  274. /package/docs/{mobileconversionresearch.1.8.10.md → mobileconversionresearch1810.md} +0 -0
  275. /package/docs/{nativeidentityresearch.1.8.11.md → nativeidentityresearch1811.md} +0 -0
  276. /package/docs/{native.wrappers.md → nativewrappers.md} +0 -0
  277. /package/docs/{planning.1.8.18.md → planning1818.md} +0 -0
  278. /package/docs/{planning.1.8.19.md → planning1819.md} +0 -0
  279. /package/docs/{planning.engine.md → planningengine.md} +0 -0
  280. /package/docs/{releasenotes.1.8.12.md → releasenotes1812.md} +0 -0
  281. /package/docs/{releasenotes.1.8.15.md → releasenotes1815.md} +0 -0
  282. /package/docs/{releasenotes.1.8.16.md → releasenotes1816.md} +0 -0
  283. /package/docs/{releasenotes.1.8.17.md → releasenotes1817.md} +0 -0
  284. /package/docs/{releasenotes.1.8.18.md → releasenotes1818.md} +0 -0
  285. /package/docs/{releasenotes.1.8.19.md → releasenotes1819.md} +0 -0
  286. /package/docs/{reorganization.1.8.8.md → reorganization188.md} +0 -0
  287. /package/docs/{reorganization.1.8.9.md → reorganization189.md} +0 -0
  288. /package/docs/{repo.analysis.1.8.21.json → repoanalysis1821.json} +0 -0
  289. /package/docs/{repo.candidates.1.8.21.jsonl → repocandidates1821.jsonl} +0 -0
  290. /package/docs/{repo.research.1.8.16.md → reporesearch1816.md} +0 -0
  291. /package/docs/{repo.research.1.8.21.md → reporesearch1821.md} +0 -0
  292. /package/docs/{repo.selected.1.8.21.json → reposelected1821.json} +0 -0
  293. /package/docs/{repo.synthesis.1.8.21.md → reposynthesis1821.md} +0 -0
  294. /package/docs/{research.1.8.18.isolation.md → research1818isolation.md} +0 -0
  295. /package/docs/{research.1.8.19.virtual.browser.md → research1819virtualbrowser.md} +0 -0
  296. /package/docs/{scanningresearch.1.8.11.md → scanningresearch1811.md} +0 -0
  297. /package/docs/{securityaudit.1.8.7.md → securityaudit187.md} +0 -0
  298. /package/docs/{securityreferences.1.8.11.md → securityreferences1811.md} +0 -0
  299. /package/docs/{securityresearch.1.8.11.md → securityresearch1811.md} +0 -0
  300. /package/docs/{signingresearch.1.8.12.md → signingresearch1812.md} +0 -0
  301. /package/docs/{tauri.glib.risk.1.8.11.md → tauriglibrisk1811.md} +0 -0
  302. /package/docs/{todo.1.8.18.md → todo1818.md} +0 -0
  303. /package/docs/{todo.1.8.19.md → todo1819.md} +0 -0
  304. /package/docs/{toolchainresearch.1.8.9.md → toolchainresearch189.md} +0 -0
  305. /package/docs/{web.duplicatecleanup.md → webduplicatecleanup.md} +0 -0
  306. /package/docs/{web.ideas.md → webideas.md} +0 -0
  307. /package/docs/{workflowimprovements.2026.08.19.md → workflowimprovements20260819.md} +0 -0
package/Dockerfile CHANGED
@@ -1,17 +1,26 @@
1
1
  # syntax=docker/dockerfile:1
2
2
  # saddle v2.0.0 grand merge — THE ONE CONTAINER FILE.
3
3
  #
4
+ # build context: this file COPYs from two trees (saddle/ and the
5
+ # engine-ownership sibling vault/), so every build runs from the
6
+ # repository root with an explicit -f: docker build -f saddle/Dockerfile .
7
+ # (add --target saddle-runtime for the node service or --target
8
+ # qemu-runtime for the guest runner). building from inside saddle/
9
+ # breaks the vault COPY - the sibling rides the context beside this
10
+ # directory, never inside it.
11
+ #
4
12
  # this Dockerfile carries BOTH container surfaces of the merged repository:
5
13
  # 1. the saddle virtual-hardware engine image (the five stages below:
6
14
  # builder, python-bridge, qemu, qemu-runtime, runtime) — the default
7
15
  # build target, published as ghcr.io/wenathlan/saddle:vhe-<version>
8
- # across three profiles and four architectures;
16
+ # across three profiles and eleven architectures;
9
17
  # 2. the saddle node-engine image (the saddle-build and saddle-runtime
10
18
  # stages at the end of this file, folded from the former
11
19
  # dockerfile.saddle) — an explicit build target
12
20
  # (`docker build --target saddle-runtime .`), the node 26 storage and
13
21
  # compute service published as ghcr.io/wenathlan/saddle:<version>
14
- # across the four-arch family standard (amd64, arm64, ppc64le, s390x
22
+ # across the eleven-arch family standard (amd64, amd64/v2, arm64,
23
+ # arm/v7, arm/v6, ppc64le, s390x, riscv64, 386, mips64le, loong64
15
24
  # — the trixie slim base line; the stage also builds the web SPA so
16
25
  # the image serves the self-hosted console via `node /app/webserver.ts`).
17
26
  #
@@ -53,17 +62,22 @@
53
62
  # build target (docker build / the engine docker run
54
63
  # recipe below).
55
64
  #
56
- # platforms: linux/amd64, linux/arm64, linux/ppc64le and linux/s390x
57
- # through buildx --platform (the four-arch registry surface); every
65
+ # platforms: linux/amd64, linux/amd64/v2, linux/arm64, linux/arm/v7,
66
+ # linux/arm/v6, linux/ppc64le, linux/s390x, linux/riscv64, linux/386,
67
+ # linux/mips64le and linux/loong64 through buildx --platform (the
68
+ # eleven-arch registry surface — the complete linux platform list
69
+ # docker/buildx carries, the owner's law: eleven OS architectures for
70
+ # every container of every application); every
58
71
  # stage compiles for the portable baseline of its target architecture
59
- # by default (x86-64 / armv8-a / power8 / z196, resolved from
60
- # TARGETARCH) so the layers stay valid on every host and every
61
- # gha-cached runner cpu; pass --build-arg VHE_MARCH=native for
72
+ # by default (x86-64 / i686 / armv8-a / armv7-a / armv6 / power8 / z196 /
73
+ # rv64gc / mips64r2 / loongarch64, resolved from
74
+ # TARGETARCH and TARGETVARIANT) so the layers stay valid on every host
75
+ # and every gha-cached runner cpu; pass --build-arg VHE_MARCH=native for
62
76
  # host-tuned local builds, or an explicit -march value when
63
77
  # cross-building for a known deployment target.
64
78
  #
65
79
  # profiles: the three profiles (max, balanced, lite) are all built for
66
- # all four architectures; each profile carries a distinct virtual CPU
80
+ # all eleven architectures; each profile carries a distinct virtual CPU
67
81
  # identity (model name, vcpus, threads, ram) baked into /etc/virtual.
68
82
  #
69
83
  # the one container file (the gateway 1.1.5 standard): the compose stack
@@ -94,7 +108,7 @@
94
108
  # -v vmdata:/data/vmdata -v webdata:/data/web \
95
109
  # -v ./vm.config.json:/engine/vm.config.json:ro \
96
110
  # -e PORT=8080 -e NODE_ENV=production -p 31280:8080 \
97
- # ghcr.io/wenathlan/saddle:vhe-2.1.6
111
+ # ghcr.io/wenathlan/saddle:vhe-2.0.154
98
112
  #
99
113
  # vheqemu (the guest runner; build it first with
100
114
  # docker build --target qemu-runtime -t saddle/qemu:11.1.0 . because the
@@ -128,7 +142,7 @@
128
142
  # -e VHE_GPU_PROFILE=b200 -e VHE_GPUS=8 -e VHE_MIG=1 \
129
143
  # -e VHE_SMI_DRIVER=575.57.08 -e VHE_SMI_CUDA=12.9 \
130
144
  # -e VHE_SMI_INTERVAL=30 -e VHE_SKIP_XVFB=1 -e VHE_SKIP_VALIDATE=1 \
131
- # ghcr.io/wenathlan/saddle:vhe-2.1.6 /bin/bash -c '
145
+ # ghcr.io/wenathlan/saddle:vhe-2.0.154 /bin/bash -c '
132
146
  # while true; do
133
147
  # /usr/local/bin/nvidia-smi "$VHE_GPU_PROFILE" "$VHE_GPUS" || true
134
148
  # sleep "$VHE_SMI_INTERVAL"
@@ -145,7 +159,7 @@
145
159
  # -v qemudata:/data/qemudata \
146
160
  # -v ./qemubridge.py:/engine/qemubridge.py:ro \
147
161
  # -e QMP_SOCKET=/run/vhe/vm.qmp -e PYTHONUNBUFFERED=1 \
148
- # ghcr.io/wenathlan/saddle:vhe-2.1.6 \
162
+ # ghcr.io/wenathlan/saddle:vhe-2.0.154 \
149
163
  # python3 /engine/qemubridge.py --socket /run/vhe/vm.qmp status
150
164
  #
151
165
  # saddle-node (the node-engine service, the former compose.yml
@@ -159,7 +173,7 @@
159
173
  # --log-driver json-file --log-opt max-size=50m --log-opt max-file=5 \
160
174
  # --tmpfs /tmp:size=2g,mode=1777 \
161
175
  # -e SADDLE_MEMORY_ENGINE=ram -e SBOT_PLATFORM= -e SBOT_CDN_URL= \
162
- # ghcr.io/wenathlan/saddle:2.1.6 \
176
+ # ghcr.io/wenathlan/saddle:2.0.154 \
163
177
  # node dist/cli.js plan
164
178
  #
165
179
  # observability (the former prometheus scraper of the full profile)
@@ -175,7 +189,7 @@
175
189
  # ever binds a hardcoded address.
176
190
 
177
191
  # Base image contract (the gateway family policy): tags only, never a
178
- # @sha256: digest. A single digest cannot serve the four-architecture
192
+ # @sha256: digest. A single digest cannot serve the eleven-architecture
179
193
  # matrix this image ships (the registry resolves the tag per platform),
180
194
  # and a digest written here would be a hardcoded hash - the checksums
181
195
  # that exist are generated by the GitHub runners and published as
@@ -204,12 +218,15 @@ ARG QEMU_VERSION="11.1.0"
204
218
  FROM ${UBUNTU} AS builder
205
219
  ARG TARGETPLATFORM
206
220
  ARG TARGETARCH
221
+ ARG TARGETVARIANT
207
222
  ARG BUILDARCH
208
223
  ARG LLVM_VERSION
209
224
  ARG NODE_VERSION
210
225
  ARG MESA_VERSION
211
- # empty = portable baseline resolved from TARGETARCH at the compile step
212
- # (x86-64 / armv8-a); "native" is the opt-in for host-tuned local builds.
226
+ # empty = portable baseline resolved from TARGETARCH (and TARGETVARIANT
227
+ # for the 32-bit arm legs) at the compile step (x86-64 / i686 / armv8-a /
228
+ # armv7-a / armv6 / power8 / z196 / rv64gc / mips64r2 / loongarch64);
229
+ # "native" is the opt-in for host-tuned local builds.
213
230
  ARG VHE_MARCH=""
214
231
  # NOTE: the VHE_PROFILE_* build-args are deliberately NOT declared in the
215
232
  # builder stage. The builder compiles mesa/node/native shims which are
@@ -287,15 +304,18 @@ RUN set -eux; \
287
304
  # it off, the build is rust-free.
288
305
 
289
306
  # node 26.7.0 (current line, v8 14.6, temporal api, NODE_MODULE_VERSION 147).
290
- # amd64 and arm64 install the pinned nodesource deb; ppc64le (any arch the
291
- # nodesource apt repo does not carry) falls back to the official nodejs.org
292
- # binary tarball, extracted straight into /usr so bin/node, include/node and
307
+ # amd64 (with its amd64/v2 variant) and arm64 install the pinned nodesource
308
+ # deb; every architecture the nodesource apt repo does not carry (ppc64le,
309
+ # s390x, riscv64, loong64, mips64le, arm and 386 - the eleven-arch law's
310
+ # non-nodesource legs) falls back to the official nodejs.org binary tarball
311
+ # (mapped to the nodejs.org arch spellings: x64, armv7l, mips64el, x86),
312
+ # extracted straight into /usr so bin/node, include/node and
293
313
  # lib/node_modules land exactly where the nodesource package (and the runtime
294
314
  # stage COPY --from=builder directives) expect them. the node headers
295
315
  # (/usr/include/node) are required by the ADDON build mode of gpumonitor.cpp.
296
316
  RUN set -eux; \
297
317
  nodesrc_ok="1"; \
298
- case "${TARGETARCH}" in ppc64le|s390x|riscv64|loongarch64) nodesrc_ok="0" ;; esac; \
318
+ case "${TARGETARCH}" in ppc64le|s390x|riscv64|loong64|loongarch64|mips64le|arm|386) nodesrc_ok="0" ;; esac; \
299
319
  if [ "$nodesrc_ok" = "1" ]; then \
300
320
  # the version-line setup script (setup_26.x) is the nodesource
301
321
  # distribution contract: no hardcoded digest in this file. The
@@ -312,7 +332,14 @@ RUN set -eux; \
312
332
  "nodejs=${NODE_VERSION}-1nodesource1" \
313
333
  || apt-get install -y --no-install-recommends nodejs; \
314
334
  else \
315
- tarball="node-v${NODE_VERSION}-linux-${TARGETARCH}.tar.xz"; \
335
+ case "${TARGETARCH}" in \
336
+ amd64) nodearch="x64" ;; \
337
+ 386|i386) nodearch="x86" ;; \
338
+ arm) nodearch="armv7l" ;; \
339
+ mips64le) nodearch="mips64el" ;; \
340
+ *) nodearch="${TARGETARCH}" ;; \
341
+ esac; \
342
+ tarball="node-v${NODE_VERSION}-linux-${nodearch}.tar.xz"; \
316
343
  curl -fsSL --retry 5 --retry-all-errors -o "/tmp/${tarball}" \
317
344
  "https://nodejs.org/dist/v${NODE_VERSION}/${tarball}"; \
318
345
  tar -xJf "/tmp/${tarball}" -C /usr --strip-components=1; \
@@ -323,9 +350,11 @@ RUN set -eux; \
323
350
  # (nodesource node 26.7.0 ships npm 11.19.0) and surgically refresh
324
351
  # the four nested dependencies whose bundled versions carry the CVEs
325
352
  # the trivy release gate rejects (brace-expansion CVE-2026-14257 /
326
- # CVE-2026-69152, ip-address CVE-2026-69192 / CVE-2026-54272 /
327
- # CVE-2026-69198, tar CVE-2026-73566, undici CVE-2026-16728 /
328
- # CVE-2026-16729 / CVE-2026-15157). published npm tarballs freeze
353
+ # CVE-2026-69152 / CVE-2026-102276 / CVE-2026-102278, ip-address
354
+ # CVE-2026-69192 / CVE-2026-54272 / CVE-2026-69198, tar
355
+ # CVE-2026-73566, undici CVE-2026-16728 / CVE-2026-16729 /
356
+ # CVE-2026-15157 / CVE-2026-109383 / CVE-2026-109869 /
357
+ # CVE-2026-19534 / CVE-2026-87018). published npm tarballs freeze
329
358
  # their bundled node_modules at publish time, so the swap alone
330
359
  # still ships brace-expansion 5.0.7; each fixed release is packed
331
360
  # separately and extracted over the nested path, then asserted: the
@@ -358,10 +387,10 @@ RUN set -eux; \
358
387
  fi; \
359
388
  echo "npm tree $fname $fgot"; \
360
389
  }; \
361
- fixdep brace-expansion 5.0.9; \
390
+ fixdep brace-expansion 5.0.11; \
362
391
  fixdep ip-address 10.3.1; \
363
392
  fixdep tar 7.5.21; \
364
- fixdep undici 6.28.0; \
393
+ fixdep undici 6.29.1; \
365
394
  rm -rf /root/.npm 2>/dev/null || true
366
395
 
367
396
  # mesa 26.2.1 from source (the "build" arm of the PPA-or-build policy):
@@ -454,17 +483,25 @@ RUN set -eux; \
454
483
  # without one). virtualizationcore.cpp additionally builds its selftest
455
484
  # binary and runs it: the stage fails if a single assert trips.
456
485
  WORKDIR /src
457
- COPY virtualhardware.c gpumonitor.cpp virtualizationcore.cpp /src/libs/
486
+ COPY saddle/virtualhardware.c saddle/gpumonitor.cpp saddle/virtualizationcore.cpp /src/libs/
458
487
  RUN set -eux; \
459
488
  # portable baseline per architecture, with the ARCH FLAG the compiler
460
489
  # family actually accepts: x86 and arm speak -march; the ppc64le gcc
461
490
  # port rejects '-march=power8' ('did you mean -mcpu=power8?') so that
462
- # architecture selects the -mcpu spelling; s390x accepts -march=z196.
491
+ # architecture selects the -mcpu spelling; s390x accepts -march=z196;
492
+ # the eleven-arch law's remaining legs resolve their own baselines
493
+ # (armv7-a / armv6 by TARGETVARIANT, rv64gc, loongarch64, mips64r2,
494
+ # i686 for the 386 leg).
463
495
  archflag="-march"; \
464
496
  case "${TARGETARCH}" in \
465
497
  arm64|aarch64) march="armv8-a" ;; \
498
+ arm) if [ "${TARGETVARIANT}" = "v7" ]; then march="armv7-a"; else march="armv6"; fi ;; \
466
499
  ppc64le) march="power8"; archflag="-mcpu" ;; \
467
500
  s390x) march="z196" ;; \
501
+ riscv64) march="rv64gc" ;; \
502
+ loong64|loongarch64) march="loongarch64" ;; \
503
+ mips64le) march="mips64r2" ;; \
504
+ 386|i386) march="i686" ;; \
468
505
  *) march="x86-64" ;; \
469
506
  esac; \
470
507
  if [ -n "${VHE_MARCH}" ]; then march="${VHE_MARCH}"; archflag="-march"; fi; \
@@ -536,7 +573,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
536
573
  # (qemu-bridge/cffi wheels) because the bridge talks raw QMP over a unix
537
574
  # socket without any native binding. the py_compile run is the syntax gate
538
575
  # (error catcher: a bridge that does not compile fails the image build).
539
- COPY qemubridge.py /bridge/qemubridge.py
576
+ COPY saddle/qemubridge.py /bridge/qemubridge.py
540
577
  RUN set -eux; \
541
578
  python3 -m py_compile /bridge/qemubridge.py; \
542
579
  python3 /bridge/qemubridge.py --help >/dev/null; \
@@ -653,20 +690,23 @@ ENTRYPOINT ["/usr/bin/tini", "--", "qemu-system-x86_64"]
653
690
  # ships native bindings for the builder platforms - the per-arch legs never
654
691
  # run it under QEMU. The base rides the family tag contract (tags only,
655
692
  # never a @sha256: digest - a single digest cannot serve the
656
- # four-architecture matrix the registry resolves per platform).
657
- FROM --platform=$BUILDPLATFORM node:26.8.1-slim AS saddle-build
693
+ # eleven-architecture matrix the registry resolves per platform).
694
+ FROM --platform=$BUILDPLATFORM node:26.13.0-slim AS saddle-build
658
695
 
659
- ARG SADDLE_VERSION
696
+ ARG SADDLE_VERSION=2.0.154
660
697
  WORKDIR /app
661
698
 
662
699
  ENV NPM_CONFIG_LEGACY_PEER_DEPS=true
663
700
 
664
- COPY package.json package-lock.json ./
701
+ COPY saddle/package.json saddle/package-lock.json ./
665
702
  RUN npm ci --ignore-scripts --legacy-peer-deps
666
- COPY . .
667
- RUN npm run build:engine \
668
- && node --check dist/cli.js \
669
- && npm run web:build:pages \
703
+ COPY saddle/ .
704
+ # the engine-ownership sibling: the saddle labels resolve
705
+ # ../vault/labelstore.ts (the node-side fork reads the source file raw),
706
+ # so the vault sources ride the context beside the saddle and land at
707
+ # /vault where the import resolves (the family context fix).
708
+ COPY vault/ /vault
709
+ RUN npm run web:build:pages \
670
710
  # the theme build emits the hashed SPA bundles straight at the app
671
711
  # root (the family static-first vite contract): stage them into a
672
712
  # clean folder so the runtime stages copy exactly the console
@@ -907,9 +947,15 @@ COPY --from=python-bridge /bridge/qemubridge.py /engine/qemubridge.py
907
947
  # the engine sources and the specification files consumed at runtime
908
948
  # (docker.config "final" stage copies the whole tree; the flat layout
909
949
  # keeps that a single COPY layer).
910
- COPY *.ts package.json tsconfig.json biome.jsonc jsdom.d.ts /engine/
911
- COPY processors.json gpus.json cores.json boards.json vm.config.json virtualhardware.json /engine/
912
- COPY qemu.config mttg.config passage.config docker.config mime.types /engine/
950
+ COPY saddle/*.ts saddle/package.json saddle/tsconfig.json saddle/biome.jsonc /engine/
951
+ COPY saddle/processors.json saddle/gpus.json saddle/cores.json saddle/boards.json saddle/vm.config.json saddle/virtualhardware.json /engine/
952
+ COPY saddle/qemu.config saddle/mttg.config saddle/passage.config saddle/docker.config saddle/mime.types /engine/
953
+ # the engine-ownership sibling: db.ts pulls labels.ts whose
954
+ # ../vault/labelstore.ts import resolves at /vault - the vault source
955
+ # rides the context beside the saddle and lands at /vault where the
956
+ # import resolves (the same family context fix as the saddle-build
957
+ # stage), so the engine webserver below finds the label store.
958
+ COPY vault/labelstore.ts /vault/labelstore.ts
913
959
 
914
960
  # the web node ships inside the main container: the mesh edition (auth,
915
961
  # sqlite database, dashboard and the browser sandbox pages) runs from the
@@ -933,8 +979,13 @@ RUN set -eux; \
933
979
  mkdir -p /etc/OpenCL/vendors; \
934
980
  case "${TARGETARCH}" in \
935
981
  arm64|aarch64) ln -sf lvp_icd.aarch64.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
982
+ arm) ln -sf lvp_icd.arm.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
936
983
  ppc64le) ln -sf lvp_icd.ppc64le.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
937
984
  s390x) ln -sf lvp_icd.s390x.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
985
+ riscv64) ln -sf lvp_icd.riscv64.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
986
+ loong64|loongarch64) ln -sf lvp_icd.loongarch64.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
987
+ mips64le) ln -sf lvp_icd.mips64.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
988
+ 386|i386) ln -sf lvp_icd.x86.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
938
989
  *) ln -sf lvp_icd.x86_64.json /usr/share/vulkan/icd.d/lvp_icd.json ;; \
939
990
  esac; \
940
991
  ldconfig; \
@@ -1288,7 +1339,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --start-interval=5s
1288
1339
  # OCI labels for registry introspection.
1289
1340
  LABEL org.opencontainers.image.title="saddle virtual-hardware engine (the grand merge)" \
1290
1341
  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" \
1291
- org.opencontainers.image.version="2.1.6" \
1342
+ org.opencontainers.image.version="2.0.154" \
1292
1343
  org.opencontainers.image.licenses="MIT" \
1293
1344
  org.opencontainers.image.source="https://github.com/wenathlan/saddle" \
1294
1345
  org.opencontainers.image.documentation="https://github.com/wenathlan/saddle/blob/main/README.md" \
@@ -1319,6 +1370,14 @@ VOLUME /data /cache/mesa_shader_cache
1319
1370
  # pid 1.
1320
1371
  ENTRYPOINT ["/entrypoint.sh"]
1321
1372
 
1373
+ # the engine service command: without a CMD the entrypoint exec "$@"
1374
+ # fell back to /bin/bash and the engine recipe (host 31280 -> container
1375
+ # 8080) bound nothing. the webserver is the console server the COPY
1376
+ # above landed at /engine: the default command starts it, and the
1377
+ # entrypoint exports PORT (8080 unless -e PORT overrides) before the
1378
+ # exec, so the service answers on 8080 out of the box.
1379
+ CMD ["node", "/engine/webserver.ts"]
1380
+
1322
1381
  # ══════════════════════════════════════════════════════════════════════
1323
1382
  # saddle node-engine stages — the storage/compute node service of the
1324
1383
  # grand merge (folded verbatim from the former dockerfile.saddle: the
@@ -1327,9 +1386,9 @@ ENTRYPOINT ["/entrypoint.sh"]
1327
1386
  # docker build --target saddle-runtime -t saddle:<version> .
1328
1387
  # ══════════════════════════════════════════════════════════════════════
1329
1388
 
1330
- FROM node:26.8.1-slim AS saddle-runtime
1389
+ FROM node:26.13.0-slim AS saddle-runtime
1331
1390
 
1332
- ARG SADDLE_VERSION
1391
+ ARG SADDLE_VERSION=2.0.154
1333
1392
  LABEL org.opencontainers.image.title="Saddle" \
1334
1393
  org.opencontainers.image.description="Storage-backed browser and compute engine (the grand-merge node service)" \
1335
1394
  org.opencontainers.image.source="https://github.com/wenathlan/saddle" \
@@ -1352,17 +1411,23 @@ RUN apt-get update \
1352
1411
  && rm -rf /var/lib/apt/lists/* \
1353
1412
  && npm install --global npm@12.0.2 \
1354
1413
  && tempdir="$(mktemp -d)" \
1355
- && npm pack brace-expansion@5.0.9 ip-address@10.3.1 tar@7.5.22 --pack-destination "$tempdir" \
1356
- && mkdir -p /usr/local/lib/node_modules/npm/node_modules/brace-expansion /usr/local/lib/node_modules/npm/node_modules/ip-address /usr/local/lib/node_modules/npm/node_modules/tar \
1357
- && tar -xzf "$tempdir/brace-expansion-5.0.9.tgz" --strip-components=1 -C /usr/local/lib/node_modules/npm/node_modules/brace-expansion \
1414
+ && npm pack brace-expansion@5.0.11 ip-address@10.3.1 tar@7.5.22 undici@6.29.1 --pack-destination "$tempdir" \
1415
+ && mkdir -p /usr/local/lib/node_modules/npm/node_modules/brace-expansion /usr/local/lib/node_modules/npm/node_modules/ip-address /usr/local/lib/node_modules/npm/node_modules/tar /usr/local/lib/node_modules/npm/node_modules/undici \
1416
+ && tar -xzf "$tempdir/brace-expansion-5.0.11.tgz" --strip-components=1 -C /usr/local/lib/node_modules/npm/node_modules/brace-expansion \
1358
1417
  && tar -xzf "$tempdir/ip-address-10.3.1.tgz" --strip-components=1 -C /usr/local/lib/node_modules/npm/node_modules/ip-address \
1359
1418
  # the npm@12.0.2 tarball freezes its bundled node_modules at publish
1360
1419
  # time (the same lesson as the vhe builder's fixdep): its tar@7.5.19
1361
1420
  # carries CVE-2026-73566 (long-path DoS), fixed in 7.5.21+. The
1362
1421
  # lockfile already resolves app tar to 7.5.22 - the global npm tree
1363
1422
  # gets the same treatment and the version is asserted after install.
1423
+ # The same freeze ships brace-expansion 5.0.9 (CVE-2026-102276 /
1424
+ # CVE-2026-102278, fixed in 5.0.10+) and undici 6.28.0 (CVE-2026-109383
1425
+ # / CVE-2026-109869 / CVE-2026-19534 / CVE-2026-87018, fixed in
1426
+ # 6.29.1+): both carriers ride the swap and the assert proves it.
1364
1427
  && tar -xzf "$tempdir/tar-7.5.22.tgz" --strip-components=1 -C /usr/local/lib/node_modules/npm/node_modules/tar \
1428
+ && tar -xzf "$tempdir/undici-6.29.1.tgz" --strip-components=1 -C /usr/local/lib/node_modules/npm/node_modules/undici \
1365
1429
  && test "$(node -p "require('/usr/local/lib/node_modules/npm/node_modules/tar/package.json').version")" = "7.5.22" \
1430
+ && test "$(node -p "require('/usr/local/lib/node_modules/npm/node_modules/undici/package.json').version")" = "6.29.1" \
1366
1431
  && rm -rf "$tempdir" \
1367
1432
  && npm ci --omit=dev --ignore-scripts --legacy-peer-deps \
1368
1433
  # prune the vendored build toolchains of optional native deps: the
@@ -1373,20 +1438,39 @@ RUN apt-get update \
1373
1438
  # degrades to a no-op at runtime - the sources are dead weight.
1374
1439
  && rm -rf node_modules/cpu-features/deps \
1375
1440
  && find node_modules -type f -name Dockerfile -delete
1376
- COPY --from=saddle-build /app/dist ./dist
1377
1441
  # the web service surface (self-hosted console): the staged spa plus the
1378
- # pure-node server stack (webserver.ts, db.ts, labels.ts, auth.ts,
1379
- # mesh.ts, sandbox.ts, sandboxprofile.ts, sandboxenvprofile.ts,
1380
- # sandboxquota.ts, mime.types, init.sql, schema.prisma) - zero npm
1381
- # dependencies, the node 26 runtime carries everything (node:sqlite,
1382
- # node:crypto, native type stripping for the .ts sources).
1442
+ # pure-node server stack - zero npm dependencies, the node 26 runtime
1443
+ # carries everything (node:sqlite, node:crypto, native type stripping
1444
+ # for the .ts sources). the console set closes the whole import graph:
1445
+ # webserver.ts pulls modalityregistry.ts, edgeplane.ts and
1446
+ # workloadlaw.ts; edgeplane.ts pulls foundation.ts and the edgelandes
1447
+ # family (edgelandes.ts, edgelandeshost.ts, edgelandesinproc.ts,
1448
+ # edgelandesvirtual.ts, edgelandesninety.ts); db.ts pulls labels.ts
1449
+ # whose ../vault/labelstore.ts import resolves at /vault (the family
1450
+ # context fix - the vault source lands beside /app the same way the
1451
+ # saddle-build stage lands it). with the graph closed, node
1452
+ # webserver.ts starts clean; before the fix the container crashed at
1453
+ # boot with module-not-found.
1383
1454
  # run the console with: docker run saddle:<version> node webserver.ts
1384
- COPY --from=saddle-build /app/webserver.ts /app/db.ts /app/labels.ts /app/auth.ts /app/mesh.ts /app/sandbox.ts /app/sandboxprofile.ts /app/sandboxenvprofile.ts /app/sandboxquota.ts /app/mime.types /app/init.sql /app/schema.prisma ./
1455
+ COPY --from=saddle-build /app/webserver.ts /app/db.ts /app/labels.ts /app/auth.ts /app/mesh.ts /app/sandbox.ts /app/sandboxprofile.ts /app/sandboxenvprofile.ts /app/sandboxquota.ts /app/modalityregistry.ts /app/edgeplane.ts /app/workloadlaw.ts /app/foundation.ts /app/edgelandes.ts /app/edgelandeshost.ts /app/edgelandesinproc.ts /app/edgelandesvirtual.ts /app/edgelandesninety.ts /app/mime.types /app/init.sql /app/schema.prisma ./
1456
+ # the label store of the console stack: labels.ts (pulled by db.ts)
1457
+ # resolves ../vault/labelstore.ts at /vault - the same family context
1458
+ # fix the saddle-build stage applies.
1459
+ COPY --from=saddle-build /vault/labelstore.ts /vault/labelstore.ts
1385
1460
  COPY --from=saddle-build /out/spa ./
1386
1461
 
1387
1462
  USER node
1388
1463
 
1389
- HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 CMD ["node", "dist/cli.js", "help"]
1464
+ # the console service doors: the webserver answers the engine api and the
1465
+ # staged spa on the saddle port (the source-is-library law runs the .ts
1466
+ # graph natively - node 26 strips the types, zero npm dependencies).
1467
+ ENV SADDLE_PORT=8080 \
1468
+ SADDLE_HOST=0.0.0.0
1469
+
1470
+ EXPOSE 8080
1471
+
1472
+ # the health probe rides the public /health route the webserver answers
1473
+ # (node fetch, zero wget dependency on the slim debian base).
1474
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 CMD ["node", "-e", "fetch('http://127.0.0.1:8080/health').then((r)=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
1390
1475
 
1391
- ENTRYPOINT ["node", "dist/cli.js"]
1392
- CMD ["help"]
1476
+ ENTRYPOINT ["node", "webserver.ts"]