@wenathlan/saddle 2.0.150 → 2.0.152

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 (296) hide show
  1. package/Dockerfile +43 -23
  2. package/README.md +4 -4
  3. package/biome.jsonc +134 -0
  4. package/dist/App.d.ts +3 -0
  5. package/dist/App.js +50 -0
  6. package/dist/Sol/Sol.d.ts +3 -0
  7. package/dist/Sol/Sol.js +46 -0
  8. package/dist/Sol/agentbrowser/agentbrowser.d.ts +9 -0
  9. package/dist/Sol/agentbrowser/agentbrowser.js +121 -0
  10. package/dist/Sol/architecture/architecture.d.ts +9 -0
  11. package/dist/Sol/architecture/architecture.js +93 -0
  12. package/dist/Sol/compute/compute.d.ts +9 -0
  13. package/dist/Sol/compute/compute.js +22 -0
  14. package/dist/Sol/console/console.d.ts +15 -0
  15. package/dist/Sol/console/console.js +292 -0
  16. package/dist/Sol/dashboard/dashboard.d.ts +10 -0
  17. package/dist/Sol/dashboard/dashboard.js +181 -0
  18. package/dist/Sol/docs/docs.d.ts +9 -0
  19. package/dist/Sol/docs/docs.js +28 -0
  20. package/dist/Sol/home/home.d.ts +35 -0
  21. package/dist/Sol/home/home.js +239 -0
  22. package/dist/Sol/integrations/integrations.d.ts +9 -0
  23. package/dist/Sol/integrations/integrations.js +83 -0
  24. package/dist/Sol/intro/intro.d.ts +7 -0
  25. package/dist/Sol/intro/intro.js +102 -0
  26. package/dist/Sol/login/login.d.ts +16 -0
  27. package/dist/Sol/login/login.js +49 -0
  28. package/dist/Sol/notfound/notfound.d.ts +9 -0
  29. package/dist/Sol/notfound/notfound.js +15 -0
  30. package/dist/Sol/onboarding/onboarding.d.ts +25 -0
  31. package/dist/Sol/onboarding/onboarding.js +60 -0
  32. package/dist/Sol/playground/playground.d.ts +9 -0
  33. package/dist/Sol/playground/playground.js +127 -0
  34. package/dist/Sol/register/register.d.ts +16 -0
  35. package/dist/Sol/register/register.js +193 -0
  36. package/dist/Sol/shell/Shell.d.ts +124 -0
  37. package/dist/Sol/shell/Shell.js +335 -0
  38. package/dist/Sol/wingets/ComputeBootladder.d.ts +6 -0
  39. package/dist/Sol/wingets/ComputeBootladder.js +71 -0
  40. package/dist/Sol/wingets/ComputeModalitycatalog.d.ts +7 -0
  41. package/dist/Sol/wingets/ComputeModalitycatalog.js +71 -0
  42. package/dist/Sol/wingets/ConsoleApibadge.d.ts +7 -0
  43. package/dist/Sol/wingets/ConsoleApibadge.js +5 -0
  44. package/dist/Sol/wingets/ConsoleEdgelaw.d.ts +6 -0
  45. package/dist/Sol/wingets/ConsoleEdgelaw.js +36 -0
  46. package/dist/Sol/wingets/ConsoleEventstimeline.d.ts +19 -0
  47. package/dist/Sol/wingets/ConsoleEventstimeline.js +12 -0
  48. package/dist/Sol/wingets/ConsoleSnapshotcontrols.d.ts +8 -0
  49. package/dist/Sol/wingets/ConsoleSnapshotcontrols.js +8 -0
  50. package/dist/Sol/wingets/ConsoleSpecpanel.d.ts +21 -0
  51. package/dist/Sol/wingets/ConsoleSpecpanel.js +75 -0
  52. package/dist/Sol/wingets/ConsoleTerminal.d.ts +22 -0
  53. package/dist/Sol/wingets/ConsoleTerminal.js +77 -0
  54. package/dist/Sol/wingets/DashboardAccountpanel.d.ts +18 -0
  55. package/dist/Sol/wingets/DashboardAccountpanel.js +65 -0
  56. package/dist/Sol/wingets/DashboardAdminpanel.d.ts +6 -0
  57. package/dist/Sol/wingets/DashboardAdminpanel.js +90 -0
  58. package/dist/Sol/wingets/DashboardAuditlog.d.ts +8 -0
  59. package/dist/Sol/wingets/DashboardAuditlog.js +50 -0
  60. package/dist/Sol/wingets/DashboardCreatesandboxform.d.ts +10 -0
  61. package/dist/Sol/wingets/DashboardCreatesandboxform.js +71 -0
  62. package/dist/Sol/wingets/DashboardEventstimeline.d.ts +8 -0
  63. package/dist/Sol/wingets/DashboardEventstimeline.js +83 -0
  64. package/dist/Sol/wingets/DashboardGlobalsandboxestable.d.ts +8 -0
  65. package/dist/Sol/wingets/DashboardGlobalsandboxestable.js +57 -0
  66. package/dist/Sol/wingets/DashboardMeshnodestable.d.ts +8 -0
  67. package/dist/Sol/wingets/DashboardMeshnodestable.js +103 -0
  68. package/dist/Sol/wingets/DashboardSandboxlist.d.ts +10 -0
  69. package/dist/Sol/wingets/DashboardSandboxlist.js +163 -0
  70. package/dist/Sol/wingets/DashboardUserstable.d.ts +8 -0
  71. package/dist/Sol/wingets/DashboardUserstable.js +78 -0
  72. package/dist/Sol/wingets/HomeEntrygate.d.ts +23 -0
  73. package/dist/Sol/wingets/HomeEntrygate.js +73 -0
  74. package/dist/Sol/wingets/HomeMetricstrip.d.ts +9 -0
  75. package/dist/Sol/wingets/HomeMetricstrip.js +4 -0
  76. package/dist/Sol/wingets/HomeRuntimediagram.d.ts +1 -0
  77. package/dist/Sol/wingets/HomeRuntimediagram.js +22 -0
  78. package/dist/Sol/wingets/LoginForm.d.ts +19 -0
  79. package/dist/Sol/wingets/LoginForm.js +141 -0
  80. package/dist/Sol/wingets/RegisterPasswordconfirm.d.ts +13 -0
  81. package/dist/Sol/wingets/RegisterPasswordconfirm.js +16 -0
  82. package/dist/Sol/wingets/RegisterPasswordmeter.d.ts +19 -0
  83. package/dist/Sol/wingets/RegisterPasswordmeter.js +65 -0
  84. package/dist/Sol/wingets/RegisterUsernamerules.d.ts +11 -0
  85. package/dist/Sol/wingets/RegisterUsernamerules.js +16 -0
  86. package/dist/Sol/wingets/index.d.ts +39 -0
  87. package/dist/Sol/wingets/index.js +39 -0
  88. package/dist/alternatives.d.ts +508 -0
  89. package/dist/alternatives.js +950 -0
  90. package/dist/api.d.ts +154 -0
  91. package/dist/api.js +174 -0
  92. package/dist/auth.d.ts +268 -0
  93. package/dist/auth.js +476 -0
  94. package/dist/automation.d.ts +425 -0
  95. package/dist/automation.js +566 -0
  96. package/dist/browser.d.ts +561 -0
  97. package/dist/browser.js +1058 -0
  98. package/dist/capacitor.config.d.ts +45 -0
  99. package/dist/capacitor.config.js +48 -0
  100. package/dist/catalog.d.ts +43 -0
  101. package/dist/catalog.js +44 -0
  102. package/dist/cli.d.ts +16 -0
  103. package/dist/cli.js +168 -0
  104. package/dist/communication.d.ts +181 -0
  105. package/dist/communication.js +376 -0
  106. package/dist/compute.d.ts +1160 -0
  107. package/dist/compute.js +2272 -0
  108. package/dist/dashboardlib.d.ts +58 -0
  109. package/dist/dashboardlib.js +161 -0
  110. package/dist/db.d.ts +569 -0
  111. package/dist/db.js +1080 -0
  112. package/dist/distribution.d.ts +528 -0
  113. package/dist/distribution.js +810 -0
  114. package/dist/drizzle.config.d.ts +20 -0
  115. package/dist/drizzle.config.js +18 -0
  116. package/dist/edgelandes.d.ts +70 -0
  117. package/dist/edgelandes.host.d.ts +26 -0
  118. package/dist/edgelandes.host.js +1089 -0
  119. package/dist/edgelandes.inproc.d.ts +27 -0
  120. package/dist/edgelandes.inproc.js +952 -0
  121. package/dist/edgelandes.js +1133 -0
  122. package/dist/edgelandes.ninety.d.ts +31 -0
  123. package/dist/edgelandes.ninety.js +174 -0
  124. package/dist/edgelandes.virtual.d.ts +25 -0
  125. package/dist/edgelandes.virtual.js +629 -0
  126. package/dist/edgeplane.d.ts +114 -0
  127. package/dist/edgeplane.js +305 -0
  128. package/dist/examplelocaljob.d.ts +1 -0
  129. package/{docs/example-localjob.ts → dist/examplelocaljob.js} +0 -1
  130. package/dist/execution.d.ts +529 -0
  131. package/dist/execution.js +760 -0
  132. package/dist/family.d.ts +16 -0
  133. package/dist/family.js +42 -0
  134. package/dist/familyurl.d.ts +21 -0
  135. package/dist/familyurl.js +24 -0
  136. package/dist/format.d.ts +18 -0
  137. package/dist/format.js +59 -0
  138. package/dist/foundation.d.ts +172 -0
  139. package/dist/foundation.js +312 -0
  140. package/dist/index.d.ts +735 -0
  141. package/dist/index.js +1020 -0
  142. package/dist/integration.d.ts +235 -0
  143. package/dist/integration.js +228 -0
  144. package/dist/intelligence.d.ts +93 -0
  145. package/dist/intelligence.js +144 -0
  146. package/dist/isolation.d.ts +128 -0
  147. package/dist/isolation.js +95 -0
  148. package/dist/labels.d.ts +665 -0
  149. package/dist/labels.js +751 -0
  150. package/dist/localauth.d.ts +127 -0
  151. package/dist/localauth.js +413 -0
  152. package/dist/media.d.ts +343 -0
  153. package/dist/media.js +985 -0
  154. package/dist/mesh.d.ts +177 -0
  155. package/dist/mesh.js +468 -0
  156. package/dist/modalityregistry.d.ts +109 -0
  157. package/dist/modalityregistry.js +1386 -0
  158. package/dist/modes.d.ts +358 -0
  159. package/dist/modes.js +133 -0
  160. package/dist/onboardingstate.d.ts +79 -0
  161. package/dist/onboardingstate.js +282 -0
  162. package/dist/orchestrator.d.ts +1338 -0
  163. package/dist/orchestrator.js +4310 -0
  164. package/dist/packager/targetcli.js +4 -0
  165. package/dist/paths.d.ts +2 -0
  166. package/dist/paths.js +14 -0
  167. package/dist/performance.d.ts +415 -0
  168. package/dist/performance.js +826 -0
  169. package/dist/quantum.d.ts +809 -0
  170. package/dist/quantum.js +2072 -0
  171. package/dist/render.d.ts +380 -0
  172. package/dist/render.js +1072 -0
  173. package/dist/runall.d.ts +2 -0
  174. package/dist/runall.js +39 -0
  175. package/dist/runtimeprobe.d.ts +4 -0
  176. package/dist/runtimeprobe.js +8 -0
  177. package/dist/sandbox.d.ts +355 -0
  178. package/dist/sandbox.js +1721 -0
  179. package/dist/sandboxenvprofile.d.ts +29 -0
  180. package/dist/sandboxenvprofile.js +89 -0
  181. package/dist/sandboxprofile.d.ts +137 -0
  182. package/dist/sandboxprofile.js +241 -0
  183. package/dist/sandboxqueue.d.ts +108 -0
  184. package/dist/sandboxqueue.js +201 -0
  185. package/dist/sandboxquota.d.ts +121 -0
  186. package/dist/sandboxquota.js +236 -0
  187. package/dist/scheduler.d.ts +595 -0
  188. package/dist/scheduler.js +1258 -0
  189. package/dist/scriptlanes.d.ts +182 -0
  190. package/dist/scriptlanes.js +660 -0
  191. package/dist/scripts.buildengine.d.ts +1 -0
  192. package/dist/scripts.buildengine.js +39 -0
  193. package/dist/scripts.securitygate.d.ts +1 -0
  194. package/dist/scripts.securitygate.js +68 -0
  195. package/dist/scripts.validateflatnative.d.ts +1 -0
  196. package/dist/scripts.validateflatnative.js +72 -0
  197. package/dist/security.d.ts +500 -0
  198. package/dist/security.js +1169 -0
  199. package/dist/seedcatalog.d.ts +13 -0
  200. package/dist/seedcatalog.js +46 -0
  201. package/dist/server.d.ts +20 -0
  202. package/dist/server.js +53 -0
  203. package/dist/speccatalog.d.ts +31 -0
  204. package/dist/speccatalog.js +163 -0
  205. package/dist/tiers.d.ts +1001 -0
  206. package/dist/tiers.js +2169 -0
  207. package/dist/utils.d.ts +2 -0
  208. package/dist/utils.js +5 -0
  209. package/dist/vaulthandoff.d.ts +141 -0
  210. package/dist/vaulthandoff.js +444 -0
  211. package/dist/virtual.d.ts +640 -0
  212. package/dist/virtual.js +1284 -0
  213. package/dist/virtualcpu.d.ts +315 -0
  214. package/dist/virtualcpu.js +1180 -0
  215. package/dist/virtualgpu.d.ts +344 -0
  216. package/dist/virtualgpu.js +1000 -0
  217. package/dist/virtualization.d.ts +606 -0
  218. package/dist/virtualization.js +1186 -0
  219. package/dist/virtualmemory.d.ts +817 -0
  220. package/dist/virtualmemory.js +1795 -0
  221. package/dist/vite.config.d.ts +3 -0
  222. package/dist/vite.config.js +43 -0
  223. package/dist/vitest.config.d.ts +2 -0
  224. package/dist/vitest.config.js +25 -0
  225. package/dist/webserver.d.ts +166 -0
  226. package/dist/webserver.js +2226 -0
  227. package/dist/workloadlaw.d.ts +133 -0
  228. package/dist/workloadlaw.js +193 -0
  229. package/docker.config +13 -6
  230. package/docs/artifactavailability.md +2 -2
  231. package/docs/{containerplatforms-2.1.0.md → containerplatforms.2.1.0.md} +1 -1
  232. package/docs/{documentmap-1.8.12.md → documentmap.1.8.12.md} +1 -1
  233. package/docs/ninety.modalities.md +108 -0
  234. package/docs/planning.ninety.md +391 -0
  235. package/docs/{releasenotes-1.8.13.md → releasenotes.1.8.13.md} +2 -2
  236. package/docs/{releasenotes-1.8.14.md → releasenotes.1.8.14.md} +1 -1
  237. package/docs/{repo-synthesis-1.8.16.md → repo.synthesis.1.8.16.md} +1 -1
  238. package/docs/{todo-1.8.15.md → todo.1.8.15.md} +1 -1
  239. package/docs/{todo-1.8.16.md → todo.1.8.16.md} +5 -5
  240. package/docs/todo.md +2 -2
  241. package/docs/workloadlaw.md +104 -0
  242. package/index.ts +4 -3
  243. package/manifest.json +1 -1
  244. package/modalityregistry.ts +1493 -0
  245. package/orchestrator.ts +1 -1
  246. package/package.json +76 -37
  247. package/docs/CONVERSA.txt +0 -1523
  248. package/docs/architecture-1.8.19.png +0 -0
  249. package/docs/assets/architecture.svg +0 -45
  250. package/docs/assets/saddle-browser-trace.webp +0 -0
  251. package/docs/assets/saddle-hero-bridge.webp +0 -0
  252. package/docs/assets/saddle-mark.webp +0 -0
  253. package/docs/assets/saddle-runtime-map.webp +0 -0
  254. package/docs/assets/saddlemark.svg +0 -13
  255. package/docs/example-publicapi.ts +0 -7
  256. package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
  257. /package/docs/{architecture-1.8.19.md → architecture.1.8.19.md} +0 -0
  258. /package/docs/{architecture-1.8.19.mmd → architecture.1.8.19.mmd} +0 -0
  259. /package/docs/{artifactresearch-1.8.9.md → artifactresearch.1.8.9.md} +0 -0
  260. /package/docs/{batches-1816-1820.md → batches.1816.to.1820.md} +0 -0
  261. /package/docs/{brancharchive-2026-08-18.md → brancharchive.2026.08.18.md} +0 -0
  262. /package/docs/{containerplatforms-1.8.17.md → containerplatforms.1.8.17.md} +0 -0
  263. /package/docs/{e2ugh-engine.md → e2ugh.engine.md} +0 -0
  264. /package/docs/{flatbuildresearch-1.8.11.md → flatbuildresearch.1.8.11.md} +0 -0
  265. /package/docs/{licenseaudit-1.8.12.md → licenseaudit.1.8.12.md} +0 -0
  266. /package/docs/{mobileconversionresearch-1.8.10.md → mobileconversionresearch.1.8.10.md} +0 -0
  267. /package/docs/{native-wrappers.md → native.wrappers.md} +0 -0
  268. /package/docs/{nativeidentityresearch-1.8.11.md → nativeidentityresearch.1.8.11.md} +0 -0
  269. /package/docs/{releasenotes-1.8.12.md → releasenotes.1.8.12.md} +0 -0
  270. /package/docs/{releasenotes-1.8.15.md → releasenotes.1.8.15.md} +0 -0
  271. /package/docs/{releasenotes-1.8.16.md → releasenotes.1.8.16.md} +0 -0
  272. /package/docs/{releasenotes-1.8.17.md → releasenotes.1.8.17.md} +0 -0
  273. /package/docs/{releasenotes-1.8.18.md → releasenotes.1.8.18.md} +0 -0
  274. /package/docs/{releasenotes-1.8.19.md → releasenotes.1.8.19.md} +0 -0
  275. /package/docs/{reorganization-1.8.8.md → reorganization.1.8.8.md} +0 -0
  276. /package/docs/{reorganization-1.8.9.md → reorganization.1.8.9.md} +0 -0
  277. /package/docs/{repo-analysis-1.8.21.json → repo.analysis.1.8.21.json} +0 -0
  278. /package/docs/{repo-candidates-1.8.21.jsonl → repo.candidates.1.8.21.jsonl} +0 -0
  279. /package/docs/{repo-research-1.8.16.md → repo.research.1.8.16.md} +0 -0
  280. /package/docs/{repo-research-1.8.21.md → repo.research.1.8.21.md} +0 -0
  281. /package/docs/{repo-selected-1.8.21.json → repo.selected.1.8.21.json} +0 -0
  282. /package/docs/{repo-synthesis-1.8.21.md → repo.synthesis.1.8.21.md} +0 -0
  283. /package/docs/{research-1.8.18-isolation.md → research.1.8.18.isolation.md} +0 -0
  284. /package/docs/{research-1.8.19-virtual-browser.md → research.1.8.19.virtual.browser.md} +0 -0
  285. /package/docs/{scanningresearch-1.8.11.md → scanningresearch.1.8.11.md} +0 -0
  286. /package/docs/{securityaudit-1.8.7.md → securityaudit.1.8.7.md} +0 -0
  287. /package/docs/{securityreferences-1.8.11.md → securityreferences.1.8.11.md} +0 -0
  288. /package/docs/{securityresearch-1.8.11.md → securityresearch.1.8.11.md} +0 -0
  289. /package/docs/{signingresearch-1.8.12.md → signingresearch.1.8.12.md} +0 -0
  290. /package/docs/{tauri-glib-risk-1.8.11.md → tauri.glib.risk.1.8.11.md} +0 -0
  291. /package/docs/{todo-1.8.18.md → todo.1.8.18.md} +0 -0
  292. /package/docs/{todo-1.8.19.md → todo.1.8.19.md} +0 -0
  293. /package/docs/{toolchainresearch-1.8.9.md → toolchainresearch.1.8.9.md} +0 -0
  294. /package/docs/{web-duplicatecleanup.md → web.duplicatecleanup.md} +0 -0
  295. /package/docs/{web-ideas.md → web.ideas.md} +0 -0
  296. /package/docs/{workflowimprovements-2026-08-19.md → workflowimprovements.2026.08.19.md} +0 -0
package/dist/labels.js ADDED
@@ -0,0 +1,751 @@
1
+ /**
2
+ * labels.ts — the copy law of saddle: every interface string lives in the
3
+ * label store, the wingets read through this typed accessor, and a
4
+ * hardcoded string inside a widget is a defect. the manifest below is the
5
+ * english source of truth extracted from the real strings of the Sol wingets
6
+ * and the page anchors; the seed ingests it into the labels store (the site
7
+ * db through db.ts on the server, the browser rows cache in the visitor
8
+ * machine) and the seed never overwrites a translated row.
9
+ *
10
+ * the browser never imports db.ts (node:sqlite cannot ride the static
11
+ * bundle): the type comes across erased, the browser seed mirrors the rows
12
+ * into the local cache the way onboardingstate.ts mirrors the seen flags.
13
+ */
14
+ /** the label revision of the manifest: bump on every copy wave so the seed
15
+ * refreshes the store rows of the changed strings. */
16
+ export const LABEL_REVISION = 4;
17
+ /** the english manifest: the page.widget.key path answers the surface text.
18
+ * every entry is the verbatim string the wingets and page anchors rendered
19
+ * before the copy wave — zero invented copy. */
20
+ export const labelmanifest = {
21
+ // the console page anchor (the sandbox surface)
22
+ 'console.shell.section': '06 / 07',
23
+ 'console.shell.label': 'Console',
24
+ 'console.shell.title': 'The sandbox runs here.',
25
+ 'console.shell.intro': 'Pick the virtual hardware, boot the microvm and type: the same commands answer locally in the browser and on your own server. No account needed to run it; sign in to keep sandboxes.',
26
+ 'console.eyebrow': 'LIVE SANDBOX / SPEC PANEL · TERMINAL · BUS EVENTS',
27
+ 'console.signin': 'sign in',
28
+ 'console.badge.api': 'connected · v{version} · up {uptime}s',
29
+ 'console.badge.local': 'running locally in the browser',
30
+ 'console.specs.title': 'sandbox specs',
31
+ 'console.declared.head': 'declared on the landing: ',
32
+ 'console.declared.tail': ' — hardware identities stay caller choices below.',
33
+ 'console.declared.base': 'base {value}',
34
+ 'console.declared.guest': 'guest {value}',
35
+ 'console.declared.arch': 'arch {value}',
36
+ 'console.start': 'start sandbox',
37
+ 'console.startAria': 'start the virtual sandbox',
38
+ 'console.note': 'self-hosted on your own server',
39
+ 'console.prompt': 'root@{host}:~#',
40
+ 'console.boot.line': 'saddle sandbox booting ({model}, {vcpus} vcpus, {ram} gb, {gpu})',
41
+ 'console.boot.ready': 'ok: sandbox running. type "help" for the command list.',
42
+ 'console.boot.failed': 'boot failed unexpectedly; check the console log',
43
+ 'console.boot.notrunning': 'the sandbox is not running',
44
+ 'console.boot.truncated': '... output truncated for display ({bytes} bytes total)',
45
+ 'console.snapshot.created': 'snapshot {id} created (memory + disk, precopy stage 1 of 1)',
46
+ 'console.stop.done': 'sandbox stopped; snapshot-less teardown complete.',
47
+ 'console.event.creating': '{model} x{vcpus} vcpus, {ram} gb ram, {gpu}',
48
+ 'console.event.created': 'sandbox {id} — {state}',
49
+ 'console.event.createFailed': 'server unreachable — running locally in the browser',
50
+ 'console.event.specsCommitted': 'sandbox {id} specs committed',
51
+ 'console.event.started': 'microvm up in 125 ms',
52
+ 'console.event.exec': '"{command}" exit {code} via {source}',
53
+ 'console.event.snapshot': '{id} for sandbox {sandbox}',
54
+ 'console.event.stopped': 'sandbox {id} torn down',
55
+ 'console.event.deleted': 'sandbox {id} destroyed',
56
+ 'console.event.deleteFailed': 'sandbox {id} unreachable',
57
+ // the console terminal widget
58
+ 'console.terminal.title': 'root@saddle — virtual container',
59
+ 'console.terminal.outputAria': 'sandbox terminal output',
60
+ 'console.terminal.inputAria': 'terminal command input; arrow keys browse history',
61
+ 'console.terminal.state.halted': 'halted',
62
+ 'console.terminal.state.booting': 'booting',
63
+ 'console.terminal.state.running': 'running',
64
+ 'console.terminal.state.stopped': 'stopped',
65
+ // the console events timeline widget
66
+ 'console.events.title': 'bus events',
67
+ 'console.events.aria': 'sandbox lifecycle event timeline',
68
+ 'console.events.empty': 'no events yet; start the sandbox.',
69
+ // the console snapshot controls widget
70
+ 'console.snapshot': 'snapshot',
71
+ 'console.snapshotAria': 'create a snapshot of the running sandbox',
72
+ 'console.stop': 'stop',
73
+ 'console.stopAria': 'stop the running sandbox',
74
+ // the console spec panel widget
75
+ 'console.spec.cpuLabel': 'cpu model',
76
+ 'console.spec.cpuAria': 'virtual cpu model',
77
+ 'console.spec.cpuOption': '{model} ({cores}c/{threads}t)',
78
+ 'console.spec.quotaLabel': 'workspace quota',
79
+ 'console.spec.quotaAria': 'persistent workspace quota',
80
+ 'console.spec.quotaOption': '{quota} MiB',
81
+ 'console.spec.cpuHint': '{arch} · {memory} · up to {max} gb · {watts} w',
82
+ 'console.spec.vcpusLabel': 'vcpus',
83
+ 'console.spec.vcpusAria': 'virtual cpu count',
84
+ 'console.spec.ramLabel': 'ram (gb)',
85
+ 'console.spec.ramAria': 'virtual memory in gigabytes, up to 18 tb',
86
+ 'console.spec.ramExactLabel': 'exact ram (gb)',
87
+ 'console.spec.ramExactAria': 'exact virtual memory in gigabytes',
88
+ 'console.spec.gpuLabel': 'gpu',
89
+ 'console.spec.gpuAria': 'virtual gpu model',
90
+ 'console.spec.gpuOption': '{name} ({memtype} {gb} gb)',
91
+ 'console.spec.gpuHint': '{arch} · {bandwidth} gb/s · mig {mig}',
92
+ 'console.spec.migSupported': 'supported',
93
+ 'console.spec.migEmulated': 'not supported (profile emulated)',
94
+ 'console.spec.migLabel': 'vram mig profile',
95
+ 'console.spec.migAria': 'gpu mig slicing profile',
96
+ 'console.spec.migOff': 'off (full device)',
97
+ 'console.spec.mig1g': '1g.24gb · 24 gb x 4',
98
+ 'console.spec.mig2g': '2g.48gb · 48 gb x 2',
99
+ 'console.spec.mig4g': '4g.96gb · 96 gb x 1',
100
+ // the dashboard page anchor (the signal & ledger surface)
101
+ 'dashboard.brand': 'saddle',
102
+ 'dashboard.tagline': 'dashboard',
103
+ 'dashboard.nodeBadge': 'node: {label}',
104
+ 'dashboard.node.pending': '...',
105
+ 'dashboard.node.standalone': 'standalone',
106
+ 'dashboard.node.edge': 'static site',
107
+ 'dashboard.userbadge.pending': '...',
108
+ 'dashboard.userbadge.local': '{name} (local)',
109
+ 'dashboard.userbadge.localAdmin': '{name} (admin, local)',
110
+ 'dashboard.userbadge.admin': '{name} (admin)',
111
+ 'dashboard.logout': 'logout',
112
+ 'dashboard.logoutAria': 'end the session and return to the sign in page',
113
+ 'dashboard.fatal.title': 'session required',
114
+ 'dashboard.fatal.apiUnreachable': 'the server is unreachable; check the address or try again later.',
115
+ 'dashboard.fatal.needsSession': 'this page needs a signed in session.',
116
+ 'dashboard.fatal.payload': 'the server answered but the account details were not understood.',
117
+ 'dashboard.fatal.noLocalSession': 'this static page has no signed-in browser session; sign in or create a local account first.',
118
+ 'dashboard.fatal.signin': 'sign in',
119
+ 'dashboard.fatal.backConsole': 'back to the sandbox',
120
+ 'dashboard.tabsAria': 'dashboard views',
121
+ 'dashboard.tab.user': 'user',
122
+ 'dashboard.tab.admin': 'admin',
123
+ 'dashboard.panel.sandboxes': 'my sandboxes',
124
+ 'dashboard.panel.account': 'my account',
125
+ 'dashboard.panel.events': 'bus events',
126
+ 'dashboard.footer.cookie': 'session cookie (httponly)',
127
+ 'dashboard.footer.storage': 'nothing sensitive stored in the browser',
128
+ 'dashboard.footer.api': 'self-hosted on your own server',
129
+ // the dashboard account panel widget
130
+ 'dashboard.account.username': 'username',
131
+ 'dashboard.account.role': 'role',
132
+ 'dashboard.account.adminRole': 'admin (allowlist: {list})',
133
+ 'dashboard.account.mode': 'mode',
134
+ 'dashboard.account.modeLocal': 'local browser account (stays on this machine, never synced; the built-in admin account survives storage resets)',
135
+ 'dashboard.account.signedIn': 'signed in',
136
+ 'dashboard.account.expires': 'expires',
137
+ 'dashboard.account.created': 'created',
138
+ 'dashboard.account.lastLogin': 'last login',
139
+ 'dashboard.account.id': 'id',
140
+ 'dashboard.account.backup': 'backup accounts',
141
+ 'dashboard.account.restore': 'restore accounts',
142
+ 'dashboard.account.backupDone': 'backup downloaded ({count} account(s)). keep the file safe; it restores every account after a full browser wipe.',
143
+ 'dashboard.account.backupEmpty': 'no accounts to back up yet.',
144
+ 'dashboard.account.backupFailed': 'the backup download failed.',
145
+ 'dashboard.account.restoreDone': '{count} account(s) restored from the backup.',
146
+ 'dashboard.account.restoreEmpty': 'no new accounts in that backup (already present or invalid).',
147
+ 'dashboard.account.importFailed': 'import failed.',
148
+ // the dashboard admin panel widget
149
+ 'dashboard.admin.na': 'n/a',
150
+ 'dashboard.admin.localNodes': '1 (this browser)',
151
+ 'dashboard.admin.localSessions': 'local',
152
+ 'dashboard.admin.overview': 'overview',
153
+ 'dashboard.card.users': 'users',
154
+ 'dashboard.card.nodes': 'nodes',
155
+ 'dashboard.card.sandboxes': 'sandboxes',
156
+ 'dashboard.card.sessions': 'sessions',
157
+ 'dashboard.card.events': 'events',
158
+ 'dashboard.card.uptime': 'uptime',
159
+ 'dashboard.admin.refresh': 'refresh all',
160
+ 'dashboard.admin.refreshAria': 'reload every admin table',
161
+ 'dashboard.admin.nodes': 'mesh nodes',
162
+ 'dashboard.admin.users': 'users',
163
+ 'dashboard.admin.sandboxes': 'sandboxes (global)',
164
+ 'dashboard.admin.audit': 'audit log',
165
+ // the dashboard audit log widget
166
+ 'dashboard.audit.unavailable': 'audit log unavailable (status {status}).',
167
+ 'dashboard.audit.unreachable': 'the audit log is unreachable.',
168
+ 'dashboard.audit.localNote': 'audit records live on the main server.',
169
+ 'dashboard.audit.tableAria': 'audit log table',
170
+ 'dashboard.audit.empty': 'no audit entries yet.',
171
+ 'dashboard.audit.colAction': 'action',
172
+ 'dashboard.audit.colUser': 'username',
173
+ 'dashboard.audit.colIp': 'ip',
174
+ 'dashboard.audit.colWhen': 'when',
175
+ // the dashboard creation form widget
176
+ 'dashboard.create.formAria': 'create a new sandbox',
177
+ 'dashboard.create.cpuLabel': 'cpu model',
178
+ 'dashboard.create.cpuAria': 'virtual cpu model',
179
+ 'dashboard.create.vcpusLabel': 'vcpus',
180
+ 'dashboard.create.vcpusAria': 'virtual cpu count',
181
+ 'dashboard.create.ramLabel': 'ram (gb)',
182
+ 'dashboard.create.ramAria': 'virtual memory in gigabytes',
183
+ 'dashboard.create.gpuLabel': 'gpu',
184
+ 'dashboard.create.gpuAria': 'virtual gpu model',
185
+ 'dashboard.create.migLabel': 'mig profile',
186
+ 'dashboard.create.migAria': 'gpu mig slicing profile',
187
+ 'dashboard.create.failedStatus': 'creation failed with status {status}.',
188
+ 'dashboard.create.unreachable': 'the server is unreachable; the sandbox was not created.',
189
+ 'dashboard.create.submit': 'create sandbox',
190
+ 'dashboard.create.submitAria': 'create a new sandbox',
191
+ 'dashboard.create.refresh': 'refresh',
192
+ 'dashboard.create.refreshAria': 'reload the sandbox list',
193
+ // the dashboard events timeline widget
194
+ 'dashboard.events.localNote': 'the timeline is live on the main server.',
195
+ 'dashboard.events.aria': 'mesh bus event timeline',
196
+ 'dashboard.events.empty': 'waiting for events...',
197
+ 'dashboard.events.pollNote': 'checks for new events every 10 s while the tab is visible.',
198
+ // the dashboard global sandboxes table widget
199
+ 'dashboard.global.unavailable': 'sandbox table unavailable (status {status}).',
200
+ 'dashboard.global.unreachable': 'the global sandbox table is unreachable.',
201
+ 'dashboard.global.localNote': 'the global sandbox table lives on the main server; your own sandboxes stay in the user view.',
202
+ 'dashboard.global.tableAria': 'global sandboxes table',
203
+ 'dashboard.global.empty': 'no sandboxes on this node.',
204
+ 'dashboard.global.colId': 'id',
205
+ 'dashboard.global.colOwner': 'owner',
206
+ 'dashboard.global.colState': 'state',
207
+ 'dashboard.global.colSpec': 'spec',
208
+ 'dashboard.global.colCreated': 'created',
209
+ 'dashboard.global.colExpires': 'expires',
210
+ // the dashboard mesh nodes table widget
211
+ 'dashboard.mesh.pollNote': 'pings are signed server side; this page never holds mesh keys.',
212
+ 'dashboard.mesh.tableAria': 'mesh nodes table',
213
+ 'dashboard.mesh.empty': 'no nodes registered yet.',
214
+ 'dashboard.mesh.nodeUnavailable': 'node table unavailable (status {status}).',
215
+ 'dashboard.mesh.nodesUnreachable': 'the node table is unreachable.',
216
+ 'dashboard.mesh.colUrl': 'url',
217
+ 'dashboard.mesh.colRegion': 'region',
218
+ 'dashboard.mesh.colStatus': 'status',
219
+ 'dashboard.mesh.colHeartbeat': 'last heartbeat',
220
+ 'dashboard.mesh.colPing': 'ping',
221
+ 'dashboard.mesh.localNode': 'this browser',
222
+ 'dashboard.mesh.localRegion': 'local',
223
+ 'dashboard.mesh.localStatus': 'local',
224
+ 'dashboard.mesh.na': 'n/a',
225
+ 'dashboard.mesh.ping': 'ping',
226
+ 'dashboard.mesh.pingAria': 'ping mesh node {url}',
227
+ 'dashboard.mesh.pinging': 'pinging...',
228
+ 'dashboard.mesh.pongMesh': 'pong {rtt} ms (mesh)',
229
+ 'dashboard.mesh.pongMeshPlain': 'pong (mesh)',
230
+ 'dashboard.mesh.pongProbe': 'pong ~{ms} ms (client probe)',
231
+ 'dashboard.mesh.unreachable': 'unreachable',
232
+ 'dashboard.mesh.nopong': '-',
233
+ // the dashboard sandbox list widget
234
+ 'dashboard.list.title': 'the sandbox list',
235
+ 'dashboard.list.aria': 'my sandboxes',
236
+ 'dashboard.list.unreachable': 'the sandbox list is unreachable right now.',
237
+ 'dashboard.list.sessionExpired': 'the session expired; sign in again.',
238
+ 'dashboard.list.deleteFailed': 'delete failed with status {status}.',
239
+ 'dashboard.list.deleteUnreachable': 'the server is unreachable; the sandbox was not deleted.',
240
+ 'dashboard.list.stop': 'stop',
241
+ 'dashboard.list.stopAria': 'stop {id}',
242
+ 'dashboard.list.open': 'open',
243
+ 'dashboard.list.openAria': 'open sandbox {id} in the terminal',
244
+ 'dashboard.list.delete': 'delete',
245
+ 'dashboard.list.deleteAria': 'delete sandbox {id}',
246
+ 'dashboard.list.specVcpus': 'x{vcpus} vcpus',
247
+ 'dashboard.list.specRam': '{ram} gb',
248
+ 'dashboard.list.specMig': 'mig {mig}',
249
+ 'dashboard.list.metaCreated': 'created {date}',
250
+ 'dashboard.list.metaExpires': 'expires {date}',
251
+ 'dashboard.list.metaExecs': 'execs {count}',
252
+ 'dashboard.list.metaFiles': 'files {count}',
253
+ 'dashboard.list.emptyNotLive': 'the sandbox list is not live on this node yet; creation still works.',
254
+ 'dashboard.list.empty': 'no sandboxes yet; create one above or start a local sandbox from the ',
255
+ 'dashboard.list.consoleLink': 'console',
256
+ 'dashboard.list.emptyPeriod': '.',
257
+ // the dashboard users table widget
258
+ 'dashboard.users.searchLabel': 'search by username',
259
+ 'dashboard.users.searchPlaceholder': 'filter...',
260
+ 'dashboard.users.searchAria': 'filter the users table by username',
261
+ 'dashboard.users.tableAria': 'users table',
262
+ 'dashboard.users.emptyLocal': 'no accounts registered in this browser.',
263
+ 'dashboard.users.empty': 'no users registered yet.',
264
+ 'dashboard.users.noMatch': 'no users match "{needle}".',
265
+ 'dashboard.users.colUsername': 'username',
266
+ 'dashboard.users.colRole': 'role',
267
+ 'dashboard.users.colLastLogin': 'last login',
268
+ 'dashboard.users.colCreated': 'created',
269
+ 'dashboard.users.localCell': 'local',
270
+ 'dashboard.users.hashesNote': 'password hashes never leave the server; this table renders account fields only.',
271
+ 'dashboard.users.unavailable': 'user table unavailable (status {status}).',
272
+ 'dashboard.users.unreachable': 'the users table is unreachable.',
273
+ // the home runtime diagram widget (the metric strip carries no copy)
274
+ 'home.diagram.aria': 'Runtime chain diagram',
275
+ 'home.diagram.topline': 'THE CHAIN / FOUR STAGES',
276
+ 'home.diagram.chain': 'repo → runner → memory → surface',
277
+ 'home.diagram.repo': 'repo',
278
+ 'home.diagram.repoDetail': 'persistent state',
279
+ 'home.diagram.runner': 'CI runner',
280
+ 'home.diagram.runnerDetail': 'virtual processor',
281
+ 'home.diagram.memory': 'memory',
282
+ 'home.diagram.memoryDetail': 'storage bridge',
283
+ 'home.diagram.surface': 'Pages / CDN',
284
+ 'home.diagram.surfaceDetail': 'shared surface',
285
+ 'home.diagram.usageFlag': 'usage flag: ',
286
+ 'home.diagram.usageFlagValue': 'process',
287
+ 'home.diagram.latencyBudget': 'latency budget: ',
288
+ 'home.diagram.latencyBudgetValue': 'remote / explicit',
289
+ // the login page anchor and form widget
290
+ 'login.brand': 'saddle',
291
+ 'login.tagline': 'sign in',
292
+ 'login.panel.title': 'account',
293
+ 'login.trust.eyebrow': 'the trust rail',
294
+ 'login.trust.aria': 'session facts',
295
+ 'login.trust.sessionLabel': 'session',
296
+ 'login.trust.sessionBody': 'the session rides an httponly cookie — nothing sensitive is stored in the browser.',
297
+ 'login.trust.transportLabel': 'transport',
298
+ 'login.trust.transportBody': 'self-hosted on your own server.',
299
+ 'login.trust.errorsLabel': 'errors',
300
+ 'login.trust.errorsBody': 'generic on purpose — no user enumeration, no cause leak.',
301
+ 'login.trust.fallbackLabel': 'fallback',
302
+ 'login.trust.fallbackBody': 'no server at this address: accounts stay local in the browser.',
303
+ 'login.footer.cookie': 'session cookie (httponly)',
304
+ 'login.footer.api': 'self-hosted on your own server',
305
+ 'login.status.local': 'accounts: local browser (static site)',
306
+ 'login.error.bothFields': 'enter both the username and the password.',
307
+ 'login.error.invalid': 'invalid username or password.',
308
+ 'login.error.noAuth': 'sign-in is not available at this address; check the server address and try again.',
309
+ 'login.error.unreachable': 'the server is unreachable; check the address or try again later.',
310
+ 'login.field.username': 'username',
311
+ 'login.hint.username': 'username only; this project has no e-mail field.',
312
+ 'login.field.password': 'password',
313
+ 'login.submit': 'sign in',
314
+ 'login.submitPending': 'signing in...',
315
+ 'login.noAccount': 'no account? ',
316
+ 'login.link.create': 'create one',
317
+ 'login.link.backConsole': 'back to the sandbox',
318
+ // the register page anchor and form wingets
319
+ 'register.brand': 'saddle',
320
+ 'register.tagline': 'create account',
321
+ 'register.panel.title': 'username + password only',
322
+ 'register.success.title': 'account created; opening your dashboard.',
323
+ 'register.success.continue': 'continue ',
324
+ 'register.success.dashboardLink': 'to the dashboard',
325
+ 'register.success.signinLink': 'sign in',
326
+ 'register.field.username': 'username',
327
+ 'register.hint.username': '3-32 chars, lowercase a-z 0-9 . - (auto-lowercased)',
328
+ 'register.field.password': 'password',
329
+ 'register.error.fixFields': 'fix the highlighted fields and try again.',
330
+ 'register.error.localFailed': 'local registration failed.',
331
+ 'register.error.noRegister': 'registration is not available at this address; check the server address and try again.',
332
+ 'register.error.generic': 'registration failed; try again.',
333
+ 'register.error.unreachable': 'the server is unreachable; check the address or try again later.',
334
+ 'register.submit': 'create account',
335
+ 'register.submitPending': 'creating...',
336
+ 'register.trust.eyebrow': 'the trust rail',
337
+ 'register.trust.aria': 'live rules and policy facts',
338
+ 'register.trust.identityLabel': 'identity',
339
+ 'register.trust.identityBody': 'username + password only — no e-mail field by project policy.',
340
+ 'register.trust.hashingLabel': 'hashing',
341
+ 'register.trust.hashingBody': 'passwords hashed with scrypt server-side.',
342
+ 'register.trust.charsetLabel': 'charset',
343
+ 'register.trust.charsetBody': '3-32 chars, lowercase a-z 0-9 . - (auto-lowercased as you type).',
344
+ 'register.trust.sessionLabel': 'session',
345
+ 'register.trust.sessionBody': 'the session rides an httponly cookie, set by the server on success.',
346
+ 'register.status.local': 'accounts: local browser (static site)',
347
+ 'register.already': 'already registered? ',
348
+ 'register.signinLink': 'sign in',
349
+ 'register.backConsole': 'back to the sandbox',
350
+ 'register.footer.policy': 'no e-mail field: project policy is username + password only',
351
+ 'register.footer.hashing': 'passwords hashed with scrypt server-side',
352
+ // the register username rules widget
353
+ 'register.rules.length': '3 to 32 characters',
354
+ 'register.rules.charset': 'only a-z, 0-9, dot and dash',
355
+ // the register password meter widget
356
+ 'register.meter.strength0': '-',
357
+ 'register.meter.strength1': 'weak',
358
+ 'register.meter.strength2': 'fair',
359
+ 'register.meter.strength3': 'good',
360
+ 'register.meter.strength4': 'strong',
361
+ 'register.meter.strengthLabel': 'strength: {name}',
362
+ 'register.meter.minHint': 'minimum 8 characters',
363
+ 'register.meter.ruleLength': 'at least 8 characters',
364
+ 'register.meter.ruleClasses': 'mix character classes (lower, upper, digit, symbol)',
365
+ // the register password confirm widget
366
+ 'register.confirm.label': 'confirm password',
367
+ 'register.confirm.match': 'passwords match.',
368
+ 'register.confirm.mismatch': 'passwords do not match.',
369
+ // the home page anchor (the landing)
370
+ 'home.hero.eyebrow': 'saddle · the instant sandbox of the family',
371
+ 'home.hero.titleLine1': 'Spin a',
372
+ 'home.hero.titleLine2': 'sandbox.',
373
+ 'home.hero.lede': 'Declared, never assembled: one line names the base, the guest and the arch — the sandbox boots it and the result ships back as a package.',
374
+ 'home.hero.formAria': 'declare a sandbox and boot the console',
375
+ 'home.hero.declareLabel': 'declare',
376
+ 'home.hero.placeholder': 'spin a sandbox — try: omarchy · max · arm64',
377
+ 'home.hero.boot': 'boot ',
378
+ 'home.hero.chipsLegend': 'the declared vocabulary',
379
+ 'home.chips.base': 'base',
380
+ 'home.chips.guest': 'guest',
381
+ 'home.chips.arch': 'arch',
382
+ 'home.declared.line': 'declared: {parts} — the boot key hands it to the console',
383
+ 'home.declared.none': 'nothing declared yet — tap a chip or type the words',
384
+ 'home.declared.base': 'base {value}',
385
+ 'home.declared.guest': 'guest {value}',
386
+ 'home.declared.arch': 'arch {value}',
387
+ 'home.matrix.aria': 'the sandbox matrix',
388
+ 'home.matrix.title': 'the sandbox matrix',
389
+ 'home.matrix.subtitle': 'three bases · bootstrap limits',
390
+ 'home.matrix.colBase': 'base',
391
+ 'home.matrix.colGuests': 'guests',
392
+ 'home.matrix.colArch': 'arch',
393
+ 'home.matrix.colVgpu': 'vgpu',
394
+ 'home.matrix.colCeiling': 'ceiling',
395
+ 'home.matrix.guests': '{n} guests',
396
+ 'home.matrix.archValue': 'arm64 · amd64',
397
+ 'home.matrix.vgpuNone': 'none',
398
+ 'home.matrix.vgpuOne': '{n} slice',
399
+ 'home.matrix.vgpuMany': '{n} slices',
400
+ 'home.matrix.ceiling': '{vcpus} vcpu · {ram} gb ram · {disk} gb disk · {minutes} min',
401
+ 'home.matrix.note': 'the documented development bootstrap limits — the table is configuration, never a product rule. guests: {oses}.',
402
+ 'home.metric.bases.label': 'runtime bases',
403
+ 'home.metric.bases.detail': 'lite / balanced / max',
404
+ 'home.metric.storage.value': '70+',
405
+ 'home.metric.storage.label': 'storage backends',
406
+ 'home.metric.storage.detail': 'rclone-compatible',
407
+ 'home.metric.forms.label': 'package forms',
408
+ 'home.metric.forms.detail': 'runtime / full / published',
409
+ 'home.thesis.railLabel': 'the thesis',
410
+ 'home.thesis.eyebrow': 'core principle / 01',
411
+ 'home.thesis.title': 'The bytes are already there. ',
412
+ 'home.thesis.titleAccent': 'The flag is the machine.',
413
+ 'home.thesis.bodyLead': 'RAM and disk are the same construct at the byte level. What changes is the usage flag: ',
414
+ 'home.thesis.keep': 'keep',
415
+ 'home.thesis.join': ' or ',
416
+ 'home.thesis.process': 'process',
417
+ 'home.thesis.bodyTail': '. Saddle makes that distinction explicit, then routes work to a runner that belongs to someone else.',
418
+ 'home.evidence.head': 'INODE / DENTRY / FILE_OPS',
419
+ 'home.evidence.index': '[01]',
420
+ 'home.evidence.storage': 'storage',
421
+ 'home.evidence.equals': '=',
422
+ 'home.evidence.memory': 'compute memory',
423
+ 'home.evidence.difference': 'difference',
424
+ 'home.evidence.usageFlag': 'usage flag',
425
+ 'home.chain.railLabel': 'the chain',
426
+ 'home.chain.eyebrow': 'REPO → RUNNER → SURFACE',
427
+ 'home.chain.title': 'A repo can behave like a CPU.',
428
+ 'home.chain.archLink': 'Open architecture ',
429
+ 'home.chain.fig': 'FIG. 02 / REMOTE RUNTIME MAP',
430
+ 'home.media.area': 'media area',
431
+ 'home.surfaces.railLabel': 'the surfaces',
432
+ 'home.surfaces.eyebrow': 'ONE ENGINE / MANY SHELLS',
433
+ 'home.surfaces.titleLine1': 'Use the same machine',
434
+ 'home.surfaces.titleLine2': 'where your work already lives.',
435
+ 'home.surfaces.available': 'available / {n}',
436
+ 'home.surface.browser.title': 'Agent Browser',
437
+ 'home.surface.browser.body': 'Capture and replay of human movement in reproducible sessions.',
438
+ 'home.surface.compute.title': 'Computational memory',
439
+ 'home.surface.compute.body': 'Repos and buckets enter the process without pretending latency does not exist.',
440
+ 'home.surface.packages.title': 'Package surfaces',
441
+ 'home.surface.packages.body': 'The same machine can appear as a CLI, library, extension or app.',
442
+ 'home.steps.aria': 'the first three moves',
443
+ 'home.steps.declare.title': 'declare',
444
+ 'home.steps.declare.body': 'Name the base, the guest and the arch — the chips are the declared vocabulary.',
445
+ 'home.steps.boot.title': 'boot',
446
+ 'home.steps.boot.body': 'The console boots the microvm: spec panel, terminal, bus events.',
447
+ 'home.steps.keep.title': 'keep',
448
+ 'home.steps.keep.body': 'Snapshot the machine, or keep it on the dashboard shelf.',
449
+ 'home.steps.link': 'open the {title} ',
450
+ 'home.quad.boot.title': 'boot',
451
+ 'home.quad.boot.body': 'the console: spec, terminal, bus events',
452
+ 'home.quad.operate.title': 'operate',
453
+ 'home.quad.operate.body': 'the dashboard: shelf, account, admin',
454
+ 'home.quad.chain.title': 'chain',
455
+ 'home.quad.chain.body': 'compute: the provider farm and the bridge',
456
+ 'home.quad.thesis.title': 'thesis',
457
+ 'home.quad.thesis.body': 'architecture: repo → runner → pages',
458
+ 'home.footer.copyright': '© 2026 Saddle / distributed by design',
459
+ 'home.footer.mono': 'storage == compute',
460
+ // the intro splash (the opening act of the first run)
461
+ 'intro.status': 'saddle is opening',
462
+ 'intro.name': 'saddle',
463
+ 'intro.role': 'the sandbox engine of the family',
464
+ 'intro.skip': 'click or press any key to skip',
465
+ // the onboarding page anchor (the first-run dialog of the window)
466
+ 'onboarding.cardAria': 'saddle first run',
467
+ 'onboarding.title': 'welcome to saddle',
468
+ 'onboarding.skip': 'skip ahead',
469
+ 'onboarding.steps': 'the app · the surfaces · enter',
470
+ 'onboarding.eyebrow': '0{index} — {step}',
471
+ 'onboarding.what.title': 'one window, the sandbox engine',
472
+ 'onboarding.what.body': 'saddle is the sandbox engine of the wenathlan family — not an operating system: one application window holding the console, the api playground, the compute tiers and the agent browser, all riding the storage == compute engine.',
473
+ 'onboarding.does.title': 'what the window hosts',
474
+ 'onboarding.enter.title': 'ready to enter',
475
+ 'onboarding.enter.body': 'the window opens on the home page and every surface rides the same sectioned rail. the theme starts light and flips in memory only — nothing is written to this machine.',
476
+ 'onboarding.back': 'back',
477
+ 'onboarding.continue': 'continue',
478
+ 'onboarding.enterCta': 'enter saddle',
479
+ // the architecture page anchor (the machine surface)
480
+ 'architecture.shell.section': '01 / 06',
481
+ 'architecture.shell.label': 'Architecture',
482
+ 'architecture.shell.title': 'The machine is the chain.',
483
+ 'architecture.shell.intro': 'Saddle treats repo, CI, pages and buckets as parts of one publishable machine — with every boundary exposed.',
484
+ 'architecture.model.eyebrow': 'THE OPERATING MODEL',
485
+ 'architecture.model.title': 'Everything is a file until the flag says otherwise.',
486
+ 'architecture.model.body1': 'A repo holds persistent state. A runner takes the processor role. Pages exposes the result as a bus and CDN. The architecture does not try to erase the boundaries between these places; it turns the boundaries into an operational API.',
487
+ 'architecture.model.body2': 'The result is a VM that can be published as a package, triggered by a workflow and rehydrated from artifacts.',
488
+ 'architecture.forms.eyebrow': 'DIAGRAM AS LEDGER / THE THREE FORMS',
489
+ 'architecture.forms.aria': 'the runtime forms ledger',
490
+ 'architecture.forms.mono': 'runtime → full → published',
491
+ 'architecture.form.runtimeNode.name': 'runtime / packages',
492
+ 'architecture.form.runtimeNode.pkg': 'npm',
493
+ 'architecture.form.runtimeNode.note': 'the engine as an importable library — the declared spec resolves, the working set mounts, nothing ships but the result.',
494
+ 'architecture.form.fullDocker.name': 'full / docker',
495
+ 'architecture.form.fullDocker.pkg': 'ghcr.io',
496
+ 'architecture.form.fullDocker.note': 'the whole machine as a container image — the runner-ready form the forges and the family clones consume.',
497
+ 'architecture.form.published.name': 'published / registries',
498
+ 'architecture.form.published.pkg': 'npm · ghcr · maven · nuget · rubygems',
499
+ 'architecture.form.published.note': 'the release train — six registry publishers share the release-tag and validation gates of one workflow.',
500
+ 'architecture.layers.eyebrow': 'LAYER MAP / 04 LAYERS',
501
+ 'architecture.layers.mono': 'PATH /repo → /runner → /pages',
502
+ 'architecture.layer.repository.name': 'Repository',
503
+ 'architecture.layer.repository.sub': 'persistent state',
504
+ 'architecture.layer.repository.body': 'docs/results/ and versioned artifacts that survive the execution cycle.',
505
+ 'architecture.layer.runner.name': 'CI runner',
506
+ 'architecture.layer.runner.sub': 'virtual processor',
507
+ 'architecture.layer.runner.body': 'workflow_dispatch and repository_dispatch turn the forge into a function.',
508
+ 'architecture.layer.memory.name': 'Memory bridge',
509
+ 'architecture.layer.memory.sub': 'storage as working set',
510
+ 'architecture.layer.memory.body': 'Buckets mount as VHD/FUSE or sync into tmpfs; VRAM stays VRAM.',
511
+ 'architecture.layer.surface.name': 'Pages / CDN',
512
+ 'architecture.layer.surface.sub': 'shared surface',
513
+ 'architecture.layer.surface.body': 'The static surface observes, triggers and delivers results without living on the local machine.',
514
+ 'architecture.chain.eyebrow': 'PROVIDER CHAIN / FIRST FREE RUNNER WINS',
515
+ 'architecture.chain.mono': 'fallback / explicit',
516
+ 'architecture.chain.providers': 'oracle-cloud · github-actions · huggingface · gitlab-ci · kaggle',
517
+ 'architecture.chain.preferred': 'preferred',
518
+ 'architecture.chain.fallback': 'fallback',
519
+ 'architecture.limit.eyebrow': 'PHYSICAL LIMIT / DO NOT HIDE',
520
+ 'architecture.limit.body': 'Remote storage is not VRAM. The bridge is valid as VHD, cache or working set; physical bandwidth still governs the system.',
521
+ // the agent browser page anchor (the evidence surface)
522
+ 'agentbrowser.shell.section': '02 / 06',
523
+ 'agentbrowser.shell.label': 'Agent Browser',
524
+ 'agentbrowser.shell.title': 'Movement becomes evidence.',
525
+ 'agentbrowser.shell.intro': 'The browser agent captures a session as data: movement, click, scroll, key and the intent to replay everything later.',
526
+ 'agentbrowser.split.eyebrow': 'CAPTURE / REPLAY',
527
+ 'agentbrowser.split.title': 'The session is an artifact, not a black box.',
528
+ 'agentbrowser.split.body1': 'Brave capture, movement replay and session recording share the same layer. Each event is stored with relative time, CSS px coordinates, target and seed. Replay reruns the sequence at configurable speed.',
529
+ 'agentbrowser.split.body2': 'For the operator, this means an auditable trail: every click can point to a screenshot, token or evidence video.',
530
+ 'agentbrowser.console.session': 'SESSION / {id}',
531
+ 'agentbrowser.console.reading': 'reading the catalog…',
532
+ 'agentbrowser.console.waiting': 'waiting for the rows…',
533
+ 'agentbrowser.console.waitingSession': 'waiting for the session rows…',
534
+ 'agentbrowser.console.empty': 'no session rows served yet.',
535
+ 'agentbrowser.console.catalog': 'catalog',
536
+ 'agentbrowser.console.metrics': 'metrics',
537
+ 'agentbrowser.console.events': '{n} events / {s} s',
538
+ 'agentbrowser.console.seed': 'seed / {seed}',
539
+ 'agentbrowser.console.browser': 'browser / {browser}',
540
+ 'agentbrowser.console.na': 'n/a',
541
+ 'agentbrowser.captcha.passed': 'passed',
542
+ 'agentbrowser.captcha.failed': 'failed',
543
+ 'agentbrowser.json.eyebrow': 'SESSION JSON / V{version}',
544
+ 'agentbrowser.json.mono': 'docs/logs/<session>.json',
545
+ 'agentbrowser.principle.dom.title': 'DOM + vision',
546
+ 'agentbrowser.principle.dom.body': 'Hybrid capture is the baseline.',
547
+ 'agentbrowser.principle.replay.title': 'Deterministic replay',
548
+ 'agentbrowser.principle.replay.body': 'Same events, configurable speed.',
549
+ 'agentbrowser.principle.evidence.title': 'Evidence first',
550
+ 'agentbrowser.principle.evidence.body': 'Screenshot, token, video.',
551
+ // the compute page anchor (the engine surface)
552
+ 'compute.shell.section': '03 / 06',
553
+ 'compute.shell.label': 'Compute',
554
+ 'compute.shell.title': 'The engine states its plan.',
555
+ 'compute.shell.intro': 'The compute face presents the modality catalog the saddle engine serves: the plan counts and every record ride the internal api on mount — nothing ships fixed inside the interface.',
556
+ 'compute.split.eyebrow': 'THE COMPUTE FACE',
557
+ 'compute.split.title': 'Ninety modalities, one honest table.',
558
+ 'compute.split.body1': 'The engine keeps the catalog; the interface only reads it. The plan counts, the boot ceilings and every record arrive through the saddle api — when the engine sleeps, the page says so instead of painting rows it does not have.',
559
+ 'compute.split.body2': 'The interface never touches the visitor browser, gpu or cpu: the sandbox and the saddle modalities act for the system over the internet.',
560
+ 'compute.note.eyebrow': 'SERVED / NEVER SHIPPED',
561
+ 'compute.note.body': 'The catalog dies with the engine, not with the page: the wingets consume the db through the internal apis, so a row changes when the engine changes it — never when the bundle ships.',
562
+ // the integrations page anchor (the surface area)
563
+ 'integrations.shell.section': '04 / 06',
564
+ 'integrations.shell.label': 'Integrations',
565
+ 'integrations.shell.title': 'One machine. Many entry points.',
566
+ 'integrations.shell.intro': "The surface changes to fit the operator's flow; the engine stays the same, with storage, runner, events and results at the center.",
567
+ 'integrations.split.eyebrow': 'SURFACE AREA',
568
+ 'integrations.split.title': 'Do not choose between package, app or workflow. Chain them.',
569
+ 'integrations.split.body1': 'Saddle can be imported, triggered, packaged or embedded. The architecture keeps a useful split: interfaces handle input and observation; the remote chain does the work.',
570
+ 'integrations.split.body2': 'That is the detail that lets you swap the shell without rewriting the machine.',
571
+ 'integrations.group.package.label': 'Package surfaces',
572
+ 'integrations.group.client.label': 'Client surfaces',
573
+ 'integrations.group.bot.label': 'Bot surfaces',
574
+ 'integrations.group.mono': '{n} surfaces',
575
+ 'integrations.item.npm.name': 'npm package',
576
+ 'integrations.item.npm.body': '@wenathlan/saddle',
577
+ 'integrations.item.cli.name': 'CLI / binary',
578
+ 'integrations.item.cli.body': 'one command, remote run',
579
+ 'integrations.item.container.name': 'GitHub Container',
580
+ 'integrations.item.container.body': 'runner-ready image',
581
+ 'integrations.item.crx.name': 'CRX extension',
582
+ 'integrations.item.crx.body': 'capture from the browser',
583
+ 'integrations.item.mobile.name': 'Android / iOS',
584
+ 'integrations.item.mobile.body': 'native shell',
585
+ 'integrations.item.desktop.name': 'Desktop app',
586
+ 'integrations.item.desktop.body': 'local shell, remote engine',
587
+ 'integrations.item.forge.name': 'Forge adapters',
588
+ 'integrations.item.forge.body': 'GitHub / GitLab / Forgejo',
589
+ 'integrations.item.n8n.name': 'n8n node',
590
+ 'integrations.item.n8n.body': 'workflow as trigger',
591
+ 'integrations.item.webhook.name': 'Webhook server',
592
+ 'integrations.item.webhook.body': 'event in, run out',
593
+ 'integrations.quote.body': '“The same engine is sometimes each of the other three.”',
594
+ 'integrations.quote.mono': 'SADDLE / PRINCIPLE 04',
595
+ // the docs page anchor (the operations index)
596
+ 'docs.shell.section': '05 / 06',
597
+ 'docs.shell.label': 'Docs',
598
+ 'docs.shell.title': 'Notes for operating the chain.',
599
+ 'docs.shell.intro': 'Progressive documentation: first the thesis, then the engine, then the surfaces that make the idea usable.',
600
+ 'docs.split.eyebrow': 'PROGRESSIVE ARC',
601
+ 'docs.split.title': 'Read how a system gets built.',
602
+ 'docs.split.body1': 'The Saddle README works as the source of truth. This surface organizes the concepts into smaller steps, so the architecture can be understood before it is triggered.',
603
+ 'docs.split.body2': 'The guides below are the first editorial layer and point to the upcoming implementation pages.',
604
+ 'docs.index.eyebrow': 'INDEX / FOUNDATION → PRODUCTIZATION',
605
+ 'docs.index.mono': '{n} notes',
606
+ 'docs.note.thesis.title': 'Start with the thesis',
607
+ 'docs.note.thesis.body': 'Storage, memory and the usage flag.',
608
+ 'docs.note.thesis.meta': 'FOUNDATION',
609
+ 'docs.note.session.title': 'Session JSON',
610
+ 'docs.note.session.body': 'The reproducible artifact behind a browser run.',
611
+ 'docs.note.session.meta': 'AGENT BROWSER',
612
+ 'docs.note.repo.title': 'Repo-as-CPU',
613
+ 'docs.note.repo.body': 'Dispatch, runners, Pages and the shared surface.',
614
+ 'docs.note.repo.meta': 'ENGINE',
615
+ 'docs.note.chain.title': 'Provider chain',
616
+ 'docs.note.chain.body': 'First free runner wins, with limits exposed.',
617
+ 'docs.note.chain.meta': 'ENGINE',
618
+ 'docs.note.gates.title': 'Build gates',
619
+ 'docs.note.gates.body': 'Planning before platform implementation.',
620
+ 'docs.note.gates.meta': 'PRODUCTIZATION',
621
+ 'docs.cta.eyebrow': 'NEXT / BUILD GATE',
622
+ 'docs.cta.title': 'Planning first. Platform next.',
623
+ 'docs.cta.body': 'The implementation path starts once the chain is clear enough to be operated.',
624
+ 'docs.cta.link': 'Open repository ',
625
+ // the playground page anchor (the internal api projection)
626
+ 'playground.shell.section': '07 / 07',
627
+ 'playground.shell.label': 'Internal API Playground',
628
+ 'playground.shell.title': 'Map the request. Do not run it.',
629
+ 'playground.shell.intro': 'This is a single-site projection of the former multi-site model. The boundaries are internal API contracts: they show what would be required, but they do not start a process, read a file, reach a provider, or spend a quota.',
630
+ 'playground.split.eyebrow': 'UNIFIED WEB / SAFE FIXTURE',
631
+ 'playground.split.title1': 'One site.',
632
+ 'playground.split.title2': 'Six boundaries.',
633
+ 'playground.split.body1': 'The playground uses a fixed binary descriptor. It does not accept uploads or arbitrary code, and it does not instantiate Wasm, a worker, a container, a browser, a database, or a remote session.',
634
+ 'playground.split.body2': '“Internal API” means typed request and response envelopes in the same application. It is not a hidden endpoint, a second site, or a remote machine.',
635
+ 'playground.boundaries.eyebrow': 'INTERNAL BOUNDARY MAP',
636
+ 'playground.boundaries.mono': 'pure / serializable / no transport',
637
+ 'playground.boundary.gateway.name': 'Gateway',
638
+ 'playground.boundary.gateway.detail': 'assigns a request identity',
639
+ 'playground.boundary.plan.name': 'Plan',
640
+ 'playground.boundary.plan.detail': 'normalizes intent and budget',
641
+ 'playground.boundary.policy.name': 'Policy',
642
+ 'playground.boundary.policy.detail': 'requires explicit agreement',
643
+ 'playground.boundary.materialize.name': 'Materialize',
644
+ 'playground.boundary.materialize.detail': 'describes, never allocates',
645
+ 'playground.boundary.execute.name': 'Execute',
646
+ 'playground.boundary.execute.detail': 'delegates or denies',
647
+ 'playground.boundary.evidence.name': 'Evidence',
648
+ 'playground.boundary.evidence.detail': 'records an honest receipt',
649
+ 'playground.modalities.eyebrow': 'MODALITY CARDS / THE WALK BY STAGES',
650
+ 'playground.modalities.aria': 'the modality cards and their stage walks',
651
+ 'playground.modalities.mono': 'one card per modality · six windows steps',
652
+ 'playground.card.default.name': 'default denial',
653
+ 'playground.card.default.code': 'EXECUTION_POLICY_DENIED',
654
+ 'playground.card.default.verdict': 'the walk clears gateway, plan, policy and materialize — execute refuses the effect and the evidence never opens.',
655
+ 'playground.card.default.tip': 'project the default denial through the six boundaries',
656
+ 'playground.card.delegated.name': 'delegated handoff',
657
+ 'playground.card.delegated.code': 'CALLER_ADAPTER_REQUIRED',
658
+ 'playground.card.delegated.verdict': 'the walk clears the same stages — execute arms the caller-owned handoff and the evidence waits for the receipt.',
659
+ 'playground.card.delegated.tip': 'project the optional handoff through the six boundaries',
660
+ 'playground.walkAria': 'the stage walk of the {name} modality',
661
+ 'playground.projection.title': 'INTERNAL API PROJECTION',
662
+ 'playground.row.request': 'request',
663
+ 'playground.row.effect': 'effect',
664
+ 'playground.row.target': 'target',
665
+ 'playground.row.outcome': 'outcome',
666
+ 'playground.row.effects': 'effects',
667
+ 'playground.footer.fixture': 'fixture only',
668
+ 'playground.footer.adapter': 'no adapter invocation',
669
+ 'playground.controls.eyebrow': 'POLICY SWITCH',
670
+ 'playground.controls.title': 'Show the difference between denial and delegation.',
671
+ 'playground.controls.body': 'The second state still does not execute. It only produces a caller-owned handoff that a separately configured adapter could evaluate later.',
672
+ 'playground.controls.projectingDefault': 'projecting: the default denial — the card picked above drives this console.',
673
+ 'playground.controls.projectingDelegated': 'projecting: the delegated handoff — the card picked above drives this console.',
674
+ 'playground.note.eyebrow': 'RESOURCE POSTURE',
675
+ 'playground.note.body': 'The static interface uses only ordinary UI rendering. It deliberately performs no binary work and has no network, persistence, browser, host-bridge, provider, or background-job capability. Any operational adapter must be supplied and authorized by its operator.',
676
+ // the not-found page anchor (the 404 empty state)
677
+ 'notfound.eyebrow': '404 · route not mapped',
678
+ 'notfound.title': 'This route never connected.',
679
+ 'notfound.body': 'The site reached a path no saddle surface claims. The session stayed clean — head back to the home page or open the agent browser.',
680
+ 'notfound.backHome': 'Back home',
681
+ 'notfound.agentBrowser': 'Open the agent browser',
682
+ };
683
+ /** the translation overrides the runtime loads from the store at boot: the
684
+ * key answers the translated text when the person changed the language. */
685
+ const overrides = new Map();
686
+ /** the browser cache of the labels table: the rows mirror the site db (the
687
+ * db is the source of truth; the cache carries the translated rows offline —
688
+ * the onboardingstate.ts precedent for the visitor machine). */
689
+ const CACHE_KEY = 'saddle.labels.rows';
690
+ function readcache() {
691
+ if (typeof window === 'undefined')
692
+ return [];
693
+ try {
694
+ const raw = window.localStorage.getItem(CACHE_KEY);
695
+ if (!raw)
696
+ return [];
697
+ const parsed = JSON.parse(raw);
698
+ return Array.isArray(parsed)
699
+ ? parsed.filter((row) => !!row && typeof row === 'object')
700
+ : [];
701
+ }
702
+ catch {
703
+ return [];
704
+ }
705
+ }
706
+ function writecache(rows) {
707
+ if (typeof window === 'undefined')
708
+ return;
709
+ try {
710
+ window.localStorage.setItem(CACHE_KEY, JSON.stringify(rows));
711
+ }
712
+ catch {
713
+ // the cache is best effort: the manifest always answers
714
+ }
715
+ }
716
+ /** the typed accessor of the copy: the only door a widget uses. */
717
+ export function label(key) {
718
+ return overrides.get(key) ?? labelmanifest[key];
719
+ }
720
+ /** the placeholder door: fills the {token} slots of one format key with the
721
+ * runtime values (the store keeps the sentence, the widget passes the data). */
722
+ export function labelfill(key, values) {
723
+ return label(key).replace(/\{(\w+)\}/g, (match, token) => values[token] ?? match);
724
+ }
725
+ /** the seed ingests the manifest into the labels store, idempotent, and the
726
+ * translated rows stay protected from the overwrite. in the browser the rows
727
+ * ride the local cache of the site db; on the server db.ts seeds the same
728
+ * manifest into the labels table through seedlabelrows. */
729
+ export async function seedlabels() {
730
+ const stored = readcache();
731
+ const rows = new Map(stored.map((row) => [row.id, row]));
732
+ let seeded = 0;
733
+ let saved = 0;
734
+ for (const [id, text] of Object.entries(labelmanifest)) {
735
+ const row = rows.get(id);
736
+ overrides.set(id, row && row.translated ? row.text : text);
737
+ if (!row || (!row.translated && row.text !== text)) {
738
+ rows.set(id, {
739
+ id,
740
+ text,
741
+ revision: LABEL_REVISION,
742
+ updatedAt: new Date().toISOString(),
743
+ ...(row?.translated ? { translated: true } : {}),
744
+ });
745
+ seeded += 1;
746
+ }
747
+ saved += 1;
748
+ }
749
+ writecache([...rows.values()]);
750
+ return { seeded, protected: saved - seeded };
751
+ }