mlx-bun 0.4.0 → 1.0.0

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 (601) hide show
  1. package/README.md +1453 -88
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +10 -8
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +12 -10
  78. package/src/{serve → server}/chat-stage.ts +27 -22
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +42 -42
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +42 -83
  85. package/src/server/generated-token-history.ts +57 -0
  86. package/src/{serve → server}/http.ts +25 -13
  87. package/src/{serve → server}/inference-request.ts +5 -5
  88. package/src/server/job-routes.ts +20 -0
  89. package/src/server/media-prompt.ts +63 -0
  90. package/src/server/memory-completion-client.ts +46 -0
  91. package/src/server/model-routes.ts +192 -0
  92. package/src/{serve → server}/openai-wire.ts +3 -2
  93. package/src/{serve → server}/pipeline.ts +1 -1
  94. package/src/server/prompt-builder.ts +13 -0
  95. package/src/server/prompt-contracts.ts +17 -0
  96. package/src/server/proxy-routes.ts +187 -0
  97. package/src/server/publishing-routes.ts +41 -0
  98. package/src/{serve → server}/request-plan.ts +8 -8
  99. package/src/{serve → server}/request-prep.ts +82 -68
  100. package/src/{serve → server}/responses-client.ts +30 -13
  101. package/src/{responses.ts → server/responses.ts} +12 -93
  102. package/src/server/routes.ts +205 -0
  103. package/src/server/start.ts +72 -0
  104. package/src/server/status-routes.ts +108 -0
  105. package/src/{serve → server}/text-completion-stage.ts +25 -4
  106. package/src/server/text-prompt.ts +12 -0
  107. package/src/{serve → server}/token-streams.ts +36 -38
  108. package/src/server/worker-routes.ts +311 -0
  109. package/src/storage/paths.ts +61 -0
  110. package/src/web/assets.ts +37 -0
  111. package/src/web/{src → browser}/api.ts +5 -23
  112. package/src/web/browser/chat-host.ts +17 -0
  113. package/src/web/browser/installed-panels.ts +6 -0
  114. package/src/web/browser/main.ts +55 -0
  115. package/src/web/browser/markdown.ts +279 -0
  116. package/src/web/browser/memory-panel.ts +9 -0
  117. package/src/web/browser/palette.ts +64 -0
  118. package/src/web/browser/protocol.ts +13 -0
  119. package/src/web/browser/shell.ts +467 -0
  120. package/src/web/{src → browser}/status.ts +32 -36
  121. package/src/web/build.ts +51 -0
  122. package/src/web/public/app.html +1054 -0
  123. package/src/web/{sw.js → public/sw.js} +4 -3
  124. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  125. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  126. package/THIRD_PARTY_LICENSES.md +0 -51
  127. package/docs/README.md +0 -94
  128. package/docs/archive/hlg-sampling.md +0 -350
  129. package/docs/archive/investigations/audio-input-plan.md +0 -356
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  174. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  175. package/docs/design/batching.md +0 -1841
  176. package/docs/design/decode-speed-program.md +0 -2349
  177. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  178. package/docs/design/generic-model-support.md +0 -705
  179. package/docs/design/kv-cache.md +0 -824
  180. package/docs/design/orpo-training.md +0 -680
  181. package/docs/design/speculative-decoding.md +0 -1990
  182. package/docs/design/turboquant.md +0 -2212
  183. package/docs/design/unified-engine-frontier-plan.md +0 -1880
  184. package/docs/design/web-chat-redesign.md +0 -695
  185. package/docs/planning/PRODUCT_ROADMAP.md +0 -594
  186. package/docs/planning/ResearchTopics.md +0 -119
  187. package/docs/planning/release-notes-v0.4.0.md +0 -45
  188. package/docs/planning/video-series.md +0 -421
  189. package/docs/reference/benchmarks.md +0 -3613
  190. package/docs/reference/cli.md +0 -585
  191. package/docs/reference/distribution.md +0 -355
  192. package/docs/reference/environment.md +0 -398
  193. package/docs/reference/glossary.md +0 -39
  194. package/docs/reference/library-api.md +0 -674
  195. package/docs/reference/memory.md +0 -260
  196. package/docs/reference/models.md +0 -334
  197. package/docs/reference/server-api.md +0 -1775
  198. package/docs/reference/server-config.md +0 -846
  199. package/docs/reference/training.md +0 -462
  200. package/docs/reference/troubleshooting.md +0 -158
  201. package/src/admission-plan.ts +0 -18
  202. package/src/audio/conformer.ts +0 -647
  203. package/src/audio/decode.ts +0 -133
  204. package/src/audio/features.ts +0 -202
  205. package/src/audio/transcode.ts +0 -67
  206. package/src/backends/mlx/assistant-target.ts +0 -46
  207. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  208. package/src/backends/mlx/autoregressive.ts +0 -108
  209. package/src/backends/mlx/batch-group.ts +0 -1790
  210. package/src/backends/mlx/cache-attachment.ts +0 -67
  211. package/src/backends/mlx/cache-layout.ts +0 -31
  212. package/src/backends/mlx/checkpoint-state.ts +0 -53
  213. package/src/backends/mlx/continuation-persistence.ts +0 -106
  214. package/src/backends/mlx/continuation-request.ts +0 -43
  215. package/src/backends/mlx/continuation.ts +0 -77
  216. package/src/backends/mlx/diffusion.ts +0 -39
  217. package/src/backends/mlx/draft-target.ts +0 -32
  218. package/src/backends/mlx/evaluation.ts +0 -105
  219. package/src/backends/mlx/fill-append.ts +0 -45
  220. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  221. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  222. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  223. package/src/backends/mlx/gateway-binding.ts +0 -130
  224. package/src/backends/mlx/graph.ts +0 -38
  225. package/src/backends/mlx/kv-codec.ts +0 -9
  226. package/src/backends/mlx/kv-maintenance.ts +0 -133
  227. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  228. package/src/backends/mlx/memory-client.ts +0 -189
  229. package/src/backends/mlx/methods.ts +0 -90
  230. package/src/backends/mlx/model-prompt.ts +0 -164
  231. package/src/backends/mlx/model-serving.ts +0 -79
  232. package/src/backends/mlx/prefill-cohort.ts +0 -89
  233. package/src/backends/mlx/prefill-rows.ts +0 -200
  234. package/src/backends/mlx/prefill.ts +0 -33
  235. package/src/backends/mlx/projected-context-rows.ts +0 -72
  236. package/src/backends/mlx/request-policy.ts +0 -20
  237. package/src/backends/mlx/request-state-policy.ts +0 -41
  238. package/src/backends/mlx/rollback.ts +0 -89
  239. package/src/backends/mlx/row-sampling.ts +0 -49
  240. package/src/backends/mlx/serial-executor.ts +0 -242
  241. package/src/backends/mlx/speculative-group.ts +0 -359
  242. package/src/backends/mlx/speculative-round.ts +0 -161
  243. package/src/backends/mlx/speculative.ts +0 -114
  244. package/src/backends/mlx/state-rows.ts +0 -104
  245. package/src/backends/mlx/state-views.ts +0 -46
  246. package/src/backends/mlx/target-layout-capability.ts +0 -35
  247. package/src/backends/mlx/text-engine.ts +0 -73
  248. package/src/backends/mlx/transitioning-kv-rows.ts +0 -165
  249. package/src/chat-template.ts +0 -382
  250. package/src/cli.ts +0 -3168
  251. package/src/config.ts +0 -399
  252. package/src/contracts/completion.ts +0 -16
  253. package/src/contracts/execution.ts +0 -60
  254. package/src/contracts/generation.ts +0 -103
  255. package/src/contracts/host.ts +0 -7
  256. package/src/contracts/pi-provider.ts +0 -30
  257. package/src/contracts/pi.ts +0 -259
  258. package/src/contracts/prefix-cache.ts +0 -23
  259. package/src/contracts/resources.ts +0 -25
  260. package/src/contracts/sampling.ts +0 -23
  261. package/src/contracts/scheduling.ts +0 -45
  262. package/src/contracts/tsconfig.json +0 -14
  263. package/src/dataset/generators.ts +0 -1087
  264. package/src/dataset/index.ts +0 -12
  265. package/src/dataset/job.ts +0 -81
  266. package/src/dataset/llm.ts +0 -71
  267. package/src/dataset/registry.ts +0 -528
  268. package/src/diffusion/diffusion-generate.ts +0 -507
  269. package/src/download.ts +0 -505
  270. package/src/embed.ts +0 -77
  271. package/src/engine/admission.ts +0 -59
  272. package/src/engine/cancellation.ts +0 -38
  273. package/src/engine/engine.ts +0 -56
  274. package/src/engine/execution-coordinator.ts +0 -70
  275. package/src/engine/execution-plan.ts +0 -53
  276. package/src/engine/resources.ts +0 -53
  277. package/src/engine/scheduler.ts +0 -72
  278. package/src/engine/session.ts +0 -247
  279. package/src/eval/README.md +0 -130
  280. package/src/eval/ifeval.ts +0 -81
  281. package/src/eval/kl-prompts.ts +0 -29
  282. package/src/eval/kl.ts +0 -590
  283. package/src/eval/perplexity.ts +0 -164
  284. package/src/eval/quality-db.ts +0 -92
  285. package/src/eval/reference-logits.ts +0 -207
  286. package/src/eval/runner.ts +0 -124
  287. package/src/eval/score.ts +0 -49
  288. package/src/eval/tasks/bfcl.ts +0 -535
  289. package/src/eval/tasks/gsm8k.ts +0 -98
  290. package/src/eval/tasks/hashhop.ts +0 -139
  291. package/src/eval/tasks/humaneval.ts +0 -275
  292. package/src/eval/tasks/ifeval.ts +0 -525
  293. package/src/eval/tasks/mmlu.ts +0 -157
  294. package/src/eval/ultrafeedback.ts +0 -60
  295. package/src/evaldb.ts +0 -199
  296. package/src/expert-io.ts +0 -393
  297. package/src/expert-offload-build.ts +0 -77
  298. package/src/expert-offload.ts +0 -76
  299. package/src/expert-residency.ts +0 -1134
  300. package/src/expert-usage.ts +0 -415
  301. package/src/fill/echo-index.ts +0 -188
  302. package/src/fill/fill-session.ts +0 -452
  303. package/src/fill/proposal.ts +0 -68
  304. package/src/fill/schema-rows.ts +0 -506
  305. package/src/fill/tool-boundary.ts +0 -103
  306. package/src/fit.ts +0 -249
  307. package/src/generate.ts +0 -1346
  308. package/src/grammar.ts +0 -591
  309. package/src/harness-pi.ts +0 -184
  310. package/src/hf-push.ts +0 -628
  311. package/src/hub-rest.ts +0 -242
  312. package/src/index.ts +0 -63
  313. package/src/inference/denoising.ts +0 -17
  314. package/src/inference/draft-acceptance.ts +0 -41
  315. package/src/inference/draft-output.ts +0 -49
  316. package/src/inference/graph.ts +0 -33
  317. package/src/inference/prefill.ts +0 -39
  318. package/src/inference/rollback.ts +0 -7
  319. package/src/jobs/index.ts +0 -31
  320. package/src/jobs/job-entry.ts +0 -107
  321. package/src/jobs/task-client.ts +0 -19
  322. package/src/jobs/types.ts +0 -2
  323. package/src/kv-scheme.ts +0 -257
  324. package/src/kv-store.ts +0 -1099
  325. package/src/lab/README.md +0 -18
  326. package/src/lab/curve/curve-designer.html +0 -303
  327. package/src/lab/curve/curve-sampler.ts +0 -122
  328. package/src/lab/expert-trace/expert-trace.ts +0 -69
  329. package/src/lab/paged-kv/paged-kv-rows.ts +0 -83
  330. package/src/lab/paged-kv/paged-kv.ts +0 -270
  331. package/src/library.ts +0 -40
  332. package/src/lora.ts +0 -408
  333. package/src/md-modules.d.ts +0 -49
  334. package/src/media-fetch.ts +0 -442
  335. package/src/memory/article.ts +0 -558
  336. package/src/memory/chunk-validation.ts +0 -150
  337. package/src/memory/chunk.ts +0 -318
  338. package/src/memory/cluster.ts +0 -351
  339. package/src/memory/coverage.ts +0 -134
  340. package/src/memory/crosslink.ts +0 -0
  341. package/src/memory/db.ts +0 -253
  342. package/src/memory/entity.ts +0 -203
  343. package/src/memory/gate.ts +0 -187
  344. package/src/memory/history.ts +0 -152
  345. package/src/memory/ingest.ts +0 -335
  346. package/src/memory/model.ts +0 -183
  347. package/src/memory/normalize.ts +0 -671
  348. package/src/memory/parse.ts +0 -22
  349. package/src/memory/pipeline.ts +0 -275
  350. package/src/memory/prompts.ts +0 -65
  351. package/src/memory/query.ts +0 -334
  352. package/src/memory/reconcile.ts +0 -734
  353. package/src/memory/redirect.ts +0 -108
  354. package/src/memory/reindex.ts +0 -325
  355. package/src/memory/resolve.ts +0 -307
  356. package/src/memory/rest.ts +0 -245
  357. package/src/memory/route.ts +0 -272
  358. package/src/memory/schedule.ts +0 -165
  359. package/src/memory/stages.ts +0 -777
  360. package/src/memory/synthesize.ts +0 -1638
  361. package/src/memory/tools.ts +0 -749
  362. package/src/memory/vault.ts +0 -1194
  363. package/src/memory/wikify.ts +0 -1064
  364. package/src/mlx/array.ts +0 -388
  365. package/src/mlx/autograd.ts +0 -304
  366. package/src/mlx/checkpoint.ts +0 -149
  367. package/src/mlx/compile.ts +0 -168
  368. package/src/mlx/custom-vjp.ts +0 -188
  369. package/src/mlx/ffi.ts +0 -512
  370. package/src/mlx/materialize.ts +0 -23
  371. package/src/mlx/metal-kernel.ts +0 -159
  372. package/src/mlx/ops.ts +0 -1021
  373. package/src/mlx/quantized-rows.ts +0 -36
  374. package/src/mlx/token-bitmask.ts +0 -52
  375. package/src/mlx/turboquant-kv-decode.ts +0 -82
  376. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  377. package/src/mlx/turboquant-ops.ts +0 -861
  378. package/src/mlx/turboquant-tables.ts +0 -237
  379. package/src/mmap.ts +0 -90
  380. package/src/model/artifact-identity.ts +0 -73
  381. package/src/model/batched-kv.ts +0 -235
  382. package/src/model/batched-mask.ts +0 -279
  383. package/src/model/batched-quant.ts +0 -212
  384. package/src/model/batched-quantized-kv.ts +0 -144
  385. package/src/model/batched-rotating-quant.ts +0 -353
  386. package/src/model/batched-rotating-state.ts +0 -149
  387. package/src/model/batched-rotating.ts +0 -338
  388. package/src/model/batched-row-storage.ts +0 -179
  389. package/src/model/batched-ssm.ts +0 -52
  390. package/src/model/batched-turboquant-kv.ts +0 -93
  391. package/src/model/compiled-decode.ts +0 -712
  392. package/src/model/decoded-kv-donor.ts +0 -12
  393. package/src/model/delayed-quantized-kv.ts +0 -72
  394. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  395. package/src/model/delayed-turboquant-kv.ts +0 -55
  396. package/src/model/diffusion-gemma.ts +0 -1026
  397. package/src/model/factory.ts +0 -189
  398. package/src/model/fingerprint.ts +0 -33
  399. package/src/model/flash-attention.ts +0 -694
  400. package/src/model/full-prefill-padding.ts +0 -56
  401. package/src/model/full-prefill-row.ts +0 -105
  402. package/src/model/gemma4-base.ts +0 -2351
  403. package/src/model/gemma4.ts +0 -1315
  404. package/src/model/generated/gemma4-12b.ts +0 -429
  405. package/src/model/generated/gemma4-26b.ts +0 -448
  406. package/src/model/generated/gemma4-e4b.ts +0 -717
  407. package/src/model/generated/index.ts +0 -18
  408. package/src/model/glm52-atlas.ts +0 -511
  409. package/src/model/glm52-cache.ts +0 -792
  410. package/src/model/glm52-config.ts +0 -262
  411. package/src/model/glm52-container.ts +0 -305
  412. package/src/model/glm52-coupling.ts +0 -388
  413. package/src/model/glm52-dsa.ts +0 -606
  414. package/src/model/glm52-expert-layout.ts +0 -253
  415. package/src/model/glm52-layout.ts +0 -152
  416. package/src/model/glm52-memory.ts +0 -500
  417. package/src/model/glm52-mla.ts +0 -792
  418. package/src/model/glm52-moe.ts +0 -223
  419. package/src/model/glm52-pilot.ts +0 -537
  420. package/src/model/glm52-reference.ts +0 -445
  421. package/src/model/glm52-residency.ts +0 -557
  422. package/src/model/glm52-resident-weights.ts +0 -135
  423. package/src/model/glm52-streamed-experts.ts +0 -453
  424. package/src/model/glm52-streamed-metal.ts +0 -610
  425. package/src/model/glm52-weights.ts +0 -503
  426. package/src/model/glm52.ts +0 -1132
  427. package/src/model/implementation.ts +0 -69
  428. package/src/model/kv-attention-view.ts +0 -67
  429. package/src/model/minicpm5.ts +0 -376
  430. package/src/model/profile.ts +0 -443
  431. package/src/model/qwen-append.ts +0 -12
  432. package/src/model/qwen-conv.ts +0 -52
  433. package/src/model/qwen3-delta-state.ts +0 -74
  434. package/src/model/qwen3-delta.ts +0 -451
  435. package/src/model/qwen3-moe.ts +0 -404
  436. package/src/model/qwen3-mrope.ts +0 -252
  437. package/src/model/qwen3.ts +0 -277
  438. package/src/model/qwen3_5-checkpoint.ts +0 -164
  439. package/src/model/qwen3_5.ts +0 -819
  440. package/src/model/rotating-kv-donor.ts +0 -35
  441. package/src/model/rotating-kv-layout.ts +0 -262
  442. package/src/model/rotating-row-transaction.ts +0 -35
  443. package/src/model/speculative-rotating-kv.ts +0 -101
  444. package/src/model/ssm-prefill-padding.ts +0 -39
  445. package/src/model/support.ts +0 -102
  446. package/src/model/trellis-balanced-scatter.ts +0 -51
  447. package/src/model/trellis-linear.ts +0 -672
  448. package/src/model/trellis-shared-m.ts +0 -151
  449. package/src/model/trellis-shared-scatter.ts +0 -144
  450. package/src/model/trellis-splitk-prefill.ts +0 -158
  451. package/src/model/trellis-tiled-prefill.ts +0 -136
  452. package/src/model/trellis-vector-expand.ts +0 -62
  453. package/src/model/trellis-wide-prefill.ts +0 -94
  454. package/src/model/turboquant-codec.ts +0 -83
  455. package/src/model/universal/archs.ts +0 -332
  456. package/src/model/universal/dense.ts +0 -612
  457. package/src/model/universal/modules.ts +0 -170
  458. package/src/model/universal/rope.ts +0 -381
  459. package/src/native/expert_io.c +0 -523
  460. package/src/native/frame_extract.swift +0 -140
  461. package/src/native-pack.ts +0 -162
  462. package/src/pi-provider.ts +0 -53
  463. package/src/pi-session.ts +0 -81
  464. package/src/pi-terminal.ts +0 -274
  465. package/src/pi-web.ts +0 -1932
  466. package/src/preflight.ts +0 -158
  467. package/src/prompt-cache.ts +0 -460
  468. package/src/quantize/allocator.ts +0 -627
  469. package/src/quantize/atomic-output.ts +0 -38
  470. package/src/quantize/calibration.ts +0 -181
  471. package/src/quantize/config-writer.ts +0 -145
  472. package/src/quantize/index.ts +0 -84
  473. package/src/quantize/job.ts +0 -162
  474. package/src/quantize/quantizer.ts +0 -666
  475. package/src/quantize/rotate.ts +0 -603
  476. package/src/quantize/safetensors-writer.ts +0 -249
  477. package/src/quantize/sensitivity.ts +0 -216
  478. package/src/quantize/trellis.ts +0 -586
  479. package/src/quantize/weight-transform.ts +0 -292
  480. package/src/registry.ts +0 -602
  481. package/src/runtime-config.ts +0 -81
  482. package/src/safetensors.ts +0 -158
  483. package/src/sampler.ts +0 -1011
  484. package/src/serve/admin-routes.ts +0 -184
  485. package/src/serve/assets/curve-terrain.html +0 -105
  486. package/src/serve/assets/training-inference-map.html +0 -575
  487. package/src/serve/aux-routes.ts +0 -132
  488. package/src/serve/batch-scheduler.ts +0 -8
  489. package/src/serve/checkpoint-identity.ts +0 -64
  490. package/src/serve/generation-gateway.ts +0 -496
  491. package/src/serve/isolate.ts +0 -609
  492. package/src/serve/kv-budget.ts +0 -14
  493. package/src/serve/lab-routes.ts +0 -341
  494. package/src/serve/lane-registry.ts +0 -45
  495. package/src/serve/model-admin-routes.ts +0 -155
  496. package/src/serve/model-binding.ts +0 -43
  497. package/src/serve/model-host.ts +0 -511
  498. package/src/serve/parent-application.ts +0 -56
  499. package/src/serve/prompt-response-trace.ts +0 -147
  500. package/src/serve/response-lease.ts +0 -24
  501. package/src/serve/session-search.ts +0 -326
  502. package/src/serve/static-routes.ts +0 -101
  503. package/src/server.ts +0 -1314
  504. package/src/spec/assistant-rows.ts +0 -92
  505. package/src/spec/assistant-source.ts +0 -126
  506. package/src/spec/cache-identity.ts +0 -22
  507. package/src/spec/deepspec-rows.ts +0 -29
  508. package/src/spec/deepspec-source.ts +0 -145
  509. package/src/spec/dflash-source.ts +0 -149
  510. package/src/spec/drafter.ts +0 -304
  511. package/src/spec/dspark/ab-stats.ts +0 -136
  512. package/src/spec/dspark/calibration.ts +0 -112
  513. package/src/spec/dspark/data-dflash.ts +0 -156
  514. package/src/spec/dspark/data.ts +0 -201
  515. package/src/spec/dspark/deepspec-module.ts +0 -776
  516. package/src/spec/dspark/generate-dflash.ts +0 -245
  517. package/src/spec/dspark/generate.ts +0 -290
  518. package/src/spec/dspark/loader.ts +0 -23
  519. package/src/spec/dspark/loss.ts +0 -213
  520. package/src/spec/dspark/module-dflash.ts +0 -560
  521. package/src/spec/dspark/module.ts +0 -540
  522. package/src/spec/dspark/quantize-drafter.ts +0 -91
  523. package/src/spec/dspark/sample.ts +0 -112
  524. package/src/spec/generate.ts +0 -276
  525. package/src/spec/glm52-mtp-graph.ts +0 -29
  526. package/src/spec/glm52-mtp-rows.ts +0 -132
  527. package/src/spec/glm52-mtp-source.ts +0 -317
  528. package/src/spec/glm52-mtp-state.ts +0 -33
  529. package/src/spec/ngram-source.ts +0 -204
  530. package/src/spec/projected-draft-rows.ts +0 -73
  531. package/src/spec/qwen-mtp-module.ts +0 -171
  532. package/src/spec/qwen-mtp-rows.ts +0 -219
  533. package/src/spec/qwen-mtp-source.ts +0 -383
  534. package/src/spec/qwen-mtp-state.ts +0 -30
  535. package/src/spec/serve-loop.ts +0 -585
  536. package/src/spec/source.ts +0 -215
  537. package/src/spec/two-model-rows.ts +0 -61
  538. package/src/spec/two-model.ts +0 -113
  539. package/src/ssd-cache.ts +0 -372
  540. package/src/ssd-durability.ts +0 -211
  541. package/src/tokenizer.ts +0 -335
  542. package/src/tool-approvals.ts +0 -131
  543. package/src/tool-call.ts +0 -695
  544. package/src/train/dataset.ts +0 -484
  545. package/src/train/diffusion-lora.ts +0 -216
  546. package/src/train/export.ts +0 -32
  547. package/src/train/flash-cce.ts +0 -1234
  548. package/src/train/forward.ts +0 -266
  549. package/src/train/fuse.ts +0 -243
  550. package/src/train/index.ts +0 -46
  551. package/src/train/job.ts +0 -205
  552. package/src/train/lora-params.ts +0 -254
  553. package/src/train/loss.ts +0 -1591
  554. package/src/train/merge.ts +0 -195
  555. package/src/train/optimizer.ts +0 -183
  556. package/src/train/prefix-shared.ts +0 -490
  557. package/src/train/rank.ts +0 -137
  558. package/src/train/segmented.ts +0 -1828
  559. package/src/train/steel-qmm-header.ts +0 -1461
  560. package/src/train/trainer.ts +0 -1221
  561. package/src/train/watch.ts +0 -542
  562. package/src/vision/diffusion-vision.ts +0 -620
  563. package/src/vision/embedder.ts +0 -168
  564. package/src/vision/preprocess.ts +0 -247
  565. package/src/vision/prompt.ts +0 -373
  566. package/src/vision/qwen3vl-preprocess.ts +0 -409
  567. package/src/vision/qwen3vl-prompt.ts +0 -196
  568. package/src/vision/qwen3vl-tower.ts +0 -555
  569. package/src/vision/siglip.ts +0 -599
  570. package/src/vision/video-frames.ts +0 -148
  571. package/src/web/app.html +0 -2143
  572. package/src/web/app.js +0 -5703
  573. package/src/web/skills/memory/SKILL.md +0 -120
  574. package/src/web/skills/web-research/SKILL.md +0 -46
  575. package/src/web/skills.ts +0 -97
  576. package/src/web/src/adapters-panel.ts +0 -288
  577. package/src/web/src/assistant.ts +0 -451
  578. package/src/web/src/chat.ts +0 -1057
  579. package/src/web/src/composer.ts +0 -959
  580. package/src/web/src/dataset.ts +0 -132
  581. package/src/web/src/finetune.ts +0 -267
  582. package/src/web/src/hub.ts +0 -428
  583. package/src/web/src/main.ts +0 -98
  584. package/src/web/src/markdown.ts +0 -0
  585. package/src/web/src/memory-panel.ts +0 -572
  586. package/src/web/src/model-picker.ts +0 -159
  587. package/src/web/src/palette.ts +0 -346
  588. package/src/web/src/protocol.ts +0 -26
  589. package/src/web/src/quantize.ts +0 -167
  590. package/src/web/src/rag.ts +0 -274
  591. package/src/web/src/sessions.ts +0 -469
  592. package/src/web/src/shell.ts +0 -804
  593. package/src/web/src/ui-catalog.ts +0 -78
  594. package/src/web/vendor/README.md +0 -61
  595. package/src/web-assets.ts +0 -47
  596. package/src/web-tools.ts +0 -478
  597. package/src/weights.ts +0 -255
  598. /package/src/{serve → server}/completion-sink.ts +0 -0
  599. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  600. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  601. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
@@ -0,0 +1,1054 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>mlx-bun</title>
7
+ <style>
8
+ /* ════════════════════════════════════════════════════════════════════
9
+ mlx-bun · unified app
10
+ One product, five sections (Chat · Quantize · Fine-tune · Dataset · Status).
11
+ Apple keynote grammar: black stage, SF Pro, gradient hero type,
12
+ hairline cards, ambient color blooms, numbers that land.
13
+ Fully self-contained — no external fonts, CDNs, or scripts.
14
+ ════════════════════════════════════════════════════════════════════ */
15
+
16
+ /* ─── design tokens (shared across every section) ─── */
17
+ :root{
18
+ --bg:#000;
19
+ --ink:#f5f5f7;
20
+ --dim:#86868b;
21
+ --dimmer:#515154;
22
+ --hairline:rgba(255,255,255,.14);
23
+ --hairline-soft:rgba(255,255,255,.07);
24
+ --hairline-strong:rgba(255,255,255,.28);
25
+ --card:rgba(255,255,255,.045);
26
+ --card-hover:rgba(255,255,255,.08);
27
+ --card-2:rgba(255,255,255,.025);
28
+ --blue:#0a84ff; --cyan:#64d2ff; --indigo:#5e5ce6; --purple:#bf5af2;
29
+ --pink:#ff375f; --orange:#ff9f0a; --yellow:#ffd60a; --green:#30d158;
30
+ --red:#ff453a;
31
+ --ease:cubic-bezier(.22,.61,.21,1);
32
+ --nav-h:60px;
33
+ --mono:"SF Mono",ui-monospace,Menlo,Monaco,monospace;
34
+ /* bloom radial-gradient stop opacities — separate tokens so the light
35
+ theme can dial them down (the gradient identity/positions/colors stay
36
+ identical, only intensity changes) */
37
+ --bloom-a:.13; --bloom-b:.16; --bloom-c:.10;
38
+ --overlay-scrim:rgba(0,0,0,.55);
39
+ --overlay-panel:rgba(22,22,24,.96);
40
+ --popover-panel:rgba(30,30,34,.98);
41
+ /* Code/log/tool-output surfaces (pre blocks, .logbox, edit textarea)
42
+ deliberately stay dark-chrome in BOTH themes — the conventional
43
+ "code block keeps its own dark surface" pattern (GitHub, VS Code
44
+ light themes, etc.), so monospace content keeps consistent contrast
45
+ regardless of the surrounding chat theme.
46
+ These MUST be opaque: the original rgba(0,0,0,.45) composited to
47
+ mid-GRAY over the light theme's white page, washing out the
48
+ near-white code ink + #86868b hljs comments (2026-07-06 visual QA).
49
+ Opaque values render identically over any page background. */
50
+ --code-bg:#121214; --code-bg-soft:#1a1a1d; --code-ink:#f5f5f7;
51
+ --nav-bg:rgba(0,0,0,.62);
52
+ --scrollbar-thumb:rgba(255,255,255,.12); --scrollbar-thumb-hover:rgba(255,255,255,.22);
53
+ }
54
+ /* ─── light theme: tasteful equivalents, same gradient identity ───
55
+ Applied via [data-theme="light"] on <html> (explicit user choice,
56
+ persisted to localStorage) OR by prefers-color-scheme:light when the
57
+ user's choice is "auto" (default — see initTheme()). */
58
+ [data-theme="light"]{
59
+ --bg:#f4f4f6;
60
+ --ink:#1d1d1f;
61
+ --dim:#6e6e73;
62
+ --dimmer:#a1a1a6;
63
+ --hairline:rgba(0,0,0,.12);
64
+ --hairline-soft:rgba(0,0,0,.06);
65
+ --hairline-strong:rgba(0,0,0,.28);
66
+ --card:rgba(0,0,0,.035);
67
+ --card-hover:rgba(0,0,0,.065);
68
+ --card-2:rgba(0,0,0,.02);
69
+ --bloom-a:.09; --bloom-b:.10; --bloom-c:.07;
70
+ --overlay-scrim:rgba(0,0,0,.28);
71
+ --overlay-panel:rgba(255,255,255,.97);
72
+ --popover-panel:rgba(255,255,255,.98);
73
+ --nav-bg:rgba(255,255,255,.72);
74
+ --scrollbar-thumb:rgba(0,0,0,.14); --scrollbar-thumb-hover:rgba(0,0,0,.26);
75
+ }
76
+ *{box-sizing:border-box;margin:0;padding:0}
77
+ html,body{height:100%}
78
+ body{
79
+ background:var(--bg);color:var(--ink);
80
+ font-family:"SF Pro Display","SF Pro Text",-apple-system,BlinkMacSystemFont,"Helvetica Neue",Helvetica,Arial,sans-serif;
81
+ -webkit-font-smoothing:antialiased;
82
+ overflow:hidden; /* app shell owns its own scroll regions */
83
+ }
84
+ ::selection{background:rgba(10,132,255,.4)}
85
+ .num{font-variant-numeric:tabular-nums}
86
+ code,.mono{font-family:var(--mono)}
87
+ code{font-size:.86em;background:rgba(127,127,127,.16);padding:2px 8px;border-radius:6px}
88
+ a{color:inherit}
89
+ ::-webkit-scrollbar{width:10px;height:10px}
90
+ ::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb);border-radius:6px;border:2px solid transparent;background-clip:content-box}
91
+ ::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover);background-clip:content-box}
92
+ ::-webkit-scrollbar-track{background:transparent}
93
+
94
+ /* gradient text helpers (lifted from status/chat pages) */
95
+ .grad{background-clip:text;-webkit-background-clip:text;color:transparent}
96
+ .g-hero{background-image:linear-gradient(96deg,var(--orange) 0%,var(--pink) 30%,var(--purple) 62%,var(--blue) 100%)}
97
+ .g-blue{background-image:linear-gradient(94deg,var(--cyan),var(--blue) 55%,var(--indigo))}
98
+ .g-green{background-image:linear-gradient(94deg,#a8ff9e,var(--green) 45%,var(--cyan))}
99
+ .g-pink{background-image:linear-gradient(94deg,var(--orange),var(--pink) 55%,var(--purple))}
100
+ .g-purple{background-image:linear-gradient(94deg,var(--purple),var(--indigo) 55%,var(--blue))}
101
+
102
+ /* ─── ambient blooms behind everything ─── */
103
+ .bloom{position:fixed;inset:-25%;pointer-events:none;z-index:0;
104
+ background:
105
+ radial-gradient(55vw 42vh at 12% 6%, rgba(255,159,10,var(--bloom-a)), transparent 68%),
106
+ radial-gradient(60vw 48vh at 88% 24%, rgba(94,92,230,var(--bloom-b)), transparent 68%),
107
+ radial-gradient(50vw 40vh at 30% 96%, rgba(10,132,255,var(--bloom-c)), transparent 68%);
108
+ filter:blur(74px);
109
+ transition:opacity 1.2s var(--ease);
110
+ }
111
+ /* Ambient bloom is a slow continuous drift, gated behind
112
+ prefers-reduced-motion: with no explicit opacity set inline
113
+ by the route dimmer, it just sits static — no keyframe loop to begin
114
+ with, so the only "animation" to guard is the opacity transition
115
+ above, which is a one-shot per-route dim, not a decorative loop. The
116
+ shimmer/pulse/blink loops below are the actual ambient animations. */
117
+ @media (prefers-reduced-motion:reduce){
118
+ .bloom{transition:none}
119
+ }
120
+
121
+ /* ═══════════════════ top navigation ═══════════════════ */
122
+ nav{
123
+ position:fixed;top:0;left:0;right:0;height:var(--nav-h);z-index:50;
124
+ display:flex;align-items:center;gap:18px;padding:0 22px;
125
+ border-bottom:1px solid var(--hairline);
126
+ background:var(--nav-bg);backdrop-filter:saturate(180%) blur(22px);
127
+ -webkit-backdrop-filter:saturate(180%) blur(22px);
128
+ }
129
+ nav .brand{font-size:18px;font-weight:700;letter-spacing:-.02em;text-decoration:none;
130
+ white-space:nowrap;flex:0 0 auto}
131
+ nav .tabs{display:flex;gap:2px;flex:1 1 auto;overflow-x:auto;scrollbar-width:none}
132
+ nav .tabs::-webkit-scrollbar{display:none}
133
+ /* Scroll-edge fades (2026-07-06 jank fix): the tab row scrolls with its
134
+ scrollbar hidden, so a clipped "Build Datase" read as broken/overlapped.
135
+ JS (updateTabFades) toggles .fade-r/.fade-l per scroll position so a
136
+ soft fade signals "more tabs this way" only when actually clipped. */
137
+ nav .tabs.fade-r{-webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 34px),transparent);
138
+ mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 34px),transparent)}
139
+ nav .tabs.fade-l{-webkit-mask-image:linear-gradient(90deg,transparent,#000 34px,#000);
140
+ mask-image:linear-gradient(90deg,transparent,#000 34px,#000)}
141
+ nav .tabs.fade-l.fade-r{-webkit-mask-image:linear-gradient(90deg,transparent,#000 34px,#000 calc(100% - 34px),transparent);
142
+ mask-image:linear-gradient(90deg,transparent,#000 34px,#000 calc(100% - 34px),transparent)}
143
+ nav .tab{
144
+ appearance:none;background:none;border:none;cursor:pointer;
145
+ color:var(--dim);font:600 14px/1 inherit;letter-spacing:-.01em;
146
+ padding:8px 14px;border-radius:10px;text-decoration:none;white-space:nowrap;
147
+ transition:color .22s var(--ease),background .22s var(--ease)}
148
+ nav .tab:hover{color:var(--ink)}
149
+ nav .tab.active{color:var(--ink);background:rgba(255,255,255,.08)}
150
+ nav .right{display:flex;align-items:center;gap:12px;flex:0 0 auto}
151
+ nav .model{font:12px var(--mono);color:var(--dim);
152
+ background:var(--card);border:1px solid var(--hairline);border-radius:8px;padding:5px 10px;
153
+ max-width:34vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
154
+ appearance:none;-webkit-appearance:none;cursor:pointer;transition:color .18s var(--ease),border-color .18s var(--ease)}
155
+ nav .model:hover{color:var(--ink);border-color:var(--hairline-strong)}
156
+ .pill{display:inline-flex;align-items:center;gap:8px;
157
+ border:1px solid var(--hairline);border-radius:999px;padding:6px 13px;
158
+ font-size:12.5px;font-weight:600;color:var(--dim);letter-spacing:.01em;white-space:nowrap}
159
+ .pill .dot{width:8px;height:8px;border-radius:50%;background:var(--dimmer);
160
+ box-shadow:0 0 0 transparent;transition:all .4s}
161
+ .pill.ok .dot{background:var(--green);box-shadow:0 0 11px var(--green)}
162
+ .pill.ok{color:var(--ink)}
163
+
164
+
165
+
166
+ .pill.bad .dot{background:var(--red);box-shadow:0 0 11px var(--red)}
167
+ .pill.warn .dot{background:var(--orange);box-shadow:0 0 11px var(--orange)}
168
+
169
+
170
+
171
+
172
+
173
+
174
+
175
+ .samplepop{position:absolute;bottom:calc(100% + 9px);right:0;z-index:40;width:300px;
176
+ max-height:min(70vh,560px);overflow-y:auto;
177
+ background:var(--popover-panel);border:1px solid var(--hairline);border-radius:13px;padding:13px 14px;
178
+ backdrop-filter:blur(22px) saturate(1.3);-webkit-backdrop-filter:blur(22px) saturate(1.3);
179
+ box-shadow:0 18px 50px rgba(0,0,0,.35);display:none;
180
+ transform:translateY(4px);opacity:0;transition:opacity .16s var(--ease),transform .16s var(--ease)}
181
+ .samplepop.open{display:block;transform:translateY(0);opacity:1}
182
+ .samplepop h4{font-size:12px;font-weight:600;color:var(--dim);letter-spacing:.02em;
183
+ text-transform:uppercase;margin:0}
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+ #nav-download{color:var(--ink);font-family:var(--mono);font-size:11.5px;font-weight:500}
217
+ #nav-download .dot{background:var(--orange);box-shadow:0 0 11px var(--orange);animation:dlpulse 1.4s ease-in-out infinite}
218
+ @keyframes dlpulse{0%,100%{opacity:.4}50%{opacity:1}}
219
+ .hf-gear,.icon-btn{appearance:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
220
+ width:34px;height:34px;border-radius:10px;background:var(--card);border:1px solid var(--hairline);
221
+ color:var(--dim);flex:0 0 auto;transition:color .22s var(--ease),background .22s var(--ease),border-color .22s var(--ease)}
222
+ .hf-gear:hover,.icon-btn:hover{color:var(--ink);background:var(--card-hover);border-color:var(--hairline-strong)}
223
+ .hf-gear.saved{color:var(--green);border-color:rgba(48,209,88,.4)}
224
+
225
+ /* mobile drawer hamburger — chat route only, hidden ≥760px via the
226
+ media query beside #chat-sidebar above */
227
+ #chat-hamburger{align-items:center;justify-content:center;gap:3px}
228
+
229
+ /* theme toggle: 3-way auto/dark/light segmented control, nav-pill sized */
230
+ #theme-toggle{display:inline-flex;border:1px solid var(--hairline);border-radius:10px;overflow:hidden;flex:0 0 auto}
231
+ #theme-toggle button{appearance:none;cursor:pointer;background:transparent;border:none;color:var(--dim);
232
+ padding:0 9px;height:34px;font-size:13px;line-height:1;transition:color .18s var(--ease),background .18s var(--ease)}
233
+ #theme-toggle button:not(:last-child){border-right:1px solid var(--hairline)}
234
+ #theme-toggle button:hover{color:var(--ink);background:var(--card-hover)}
235
+ #theme-toggle button.active{color:var(--ink);background:var(--card-hover)}
236
+ #theme-toggle button:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
237
+ /* Auto's ◐ icon only appears when the text label hides at narrow widths
238
+ (see the 900px media block) — never both, never neither. */
239
+ #theme-toggle .tt-icon{display:none}
240
+
241
+ /* Developer toggle: a small switch, same nav-pill
242
+ sizing language as #theme-toggle, showing/hiding the Quantize/Fine-tune/
243
+ Build Dataset/Status/Curves/Routes tabs. aria-pressed reflects state
244
+ (kept in sync by shell.ts's applyDeveloperMode). */
245
+ #nav-developer{appearance:none;cursor:pointer;display:inline-flex;align-items:center;gap:7px;
246
+ border:1px solid var(--hairline);border-radius:10px;background:transparent;color:var(--dim);
247
+ padding:0 10px;height:34px;font-size:12.5px;font-weight:600;letter-spacing:.01em;flex:0 0 auto;
248
+ transition:color .18s var(--ease),background .18s var(--ease),border-color .18s var(--ease)}
249
+ #nav-developer:hover{color:var(--ink);background:var(--card-hover);border-color:var(--hairline-strong)}
250
+ #nav-developer:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
251
+ #nav-developer .nd-dot{width:8px;height:8px;border-radius:50%;background:var(--dimmer);flex:0 0 auto;
252
+ transition:background .18s var(--ease)}
253
+ #nav-developer .nd-dot.on{background:var(--green)}
254
+ #nav-developer[aria-checked="true"]{color:var(--ink)}
255
+
256
+ /* ─── keyboard shortcut sheet (Cmd/Ctrl+/) ─── */
257
+ #shortcut-overlay{position:fixed;inset:0;z-index:210;display:none;align-items:flex-start;justify-content:center;
258
+ background:var(--overlay-scrim);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:calc(var(--nav-h) + 24px) 20px 20px}
259
+ #shortcut-overlay.open{display:flex;animation:fade .2s var(--ease)}
260
+ #shortcut-modal{width:min(480px,100%);max-height:min(76vh,620px);overflow-y:auto;background:var(--overlay-panel);
261
+ border:1px solid var(--hairline);border-radius:20px;padding:22px 26px;box-shadow:0 30px 80px rgba(0,0,0,.35)}
262
+ .sk-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
263
+ .sk-title{font-size:18px;font-weight:700;letter-spacing:-.02em}
264
+ .sk-close{appearance:none;background:none;border:none;cursor:pointer;color:var(--dim);font-size:16px;
265
+ width:30px;height:30px;border-radius:8px;transition:color .2s,background .2s}
266
+ .sk-close:hover{color:var(--ink);background:var(--card-hover)}
267
+ .sk-row{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:8px 0;
268
+ border-bottom:1px solid var(--hairline-soft)}
269
+ .sk-row:last-child{border-bottom:none}
270
+ .sk-desc{font-size:13.5px;color:var(--ink)}
271
+ .sk-keys{display:flex;gap:5px;flex:0 0 auto}
272
+ .sk-key{font:600 11.5px var(--mono);color:var(--ink);background:var(--card);border:1px solid var(--hairline);
273
+ border-radius:6px;padding:3px 8px;min-width:20px;text-align:center}
274
+
275
+ /* ─── HF settings overlay ─── */
276
+ #hf-overlay{position:fixed;inset:0;z-index:200;display:none;align-items:flex-start;justify-content:center;
277
+ background:var(--overlay-scrim);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:calc(var(--nav-h) + 24px) 20px 20px}
278
+ #hf-overlay.open{display:flex;animation:fade .3s var(--ease)}
279
+ #hf-modal{width:min(460px,100%);background:var(--overlay-panel);border:1px solid var(--hairline);border-radius:20px;
280
+ padding:24px 26px;box-shadow:0 30px 80px rgba(0,0,0,.35)}
281
+ .hf-modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
282
+ .hf-modal-title{font-size:20px;font-weight:700;letter-spacing:-.02em}
283
+ .hf-modal-sub{font-size:13.5px;color:var(--dim);margin-bottom:20px;line-height:1.5}
284
+ .hf-close{appearance:none;background:none;border:none;cursor:pointer;color:var(--dim);font-size:16px;
285
+ width:30px;height:30px;border-radius:8px;transition:color .2s,background .2s}
286
+ .hf-close:hover{color:var(--ink);background:var(--card-hover)}
287
+
288
+ /* ─── Settings modal sections ─── */
289
+ .settings-section{margin:0 0 20px;padding:0 0 20px;border-bottom:1px solid var(--hairline-soft)}
290
+ .settings-section:last-child{border-bottom:none;padding-bottom:0;margin-bottom:0}
291
+ .settings-h{font-size:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--dim);margin:0 0 12px}
292
+ .settings-toggle-row{display:flex;align-items:center;gap:10px;font-size:13.5px;color:var(--ink);
293
+ cursor:pointer;font-weight:500;margin-bottom:8px}
294
+ .settings-toggle-row input{width:auto;margin:0;accent-color:var(--blue)}
295
+ .settings-note{font-size:12px;color:var(--orange);margin:8px 0 0;line-height:1.5}
296
+ #settings-approvals-list{margin-top:12px}
297
+ .settings-approvals-empty{font-size:12.5px;color:var(--dimmer)}
298
+ .settings-approval-row{display:flex;align-items:center;gap:10px;padding:7px 0;font-size:13px;
299
+ border-top:1px solid var(--hairline-soft)}
300
+ .settings-approval-row:first-child{border-top:none}
301
+ .settings-approval-row .satool{font:600 12.5px var(--mono);color:var(--ink);flex:1 1 auto}
302
+ .settings-approval-row .saforget{appearance:none;cursor:pointer;background:none;border:1px solid var(--hairline);
303
+ color:var(--dim);border-radius:7px;padding:3px 9px;font-size:11.5px;font-weight:600;flex:0 0 auto;
304
+ transition:color .18s var(--ease),border-color .18s var(--ease)}
305
+ .settings-approval-row .saforget:hover{color:var(--red);border-color:rgba(255,69,58,.4)}
306
+
307
+ /* ─── inline push-to-hub panel (in done-step cards) ─── */
308
+ .pushpanel{margin-top:14px;border-top:1px solid var(--hairline-soft);padding-top:14px}
309
+ .pushpanel .field{margin-bottom:12px}
310
+ .pushpanel label.chk{display:flex;align-items:center;gap:9px;font-size:13.5px;color:var(--ink);cursor:pointer;font-weight:500}
311
+ .pushpanel label.chk input{width:auto;margin:0;accent-color:var(--blue)}
312
+
313
+
314
+
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+ /* ═══════════════════ app shell / routing ═══════════════════ */
335
+ #app{position:fixed;inset:var(--nav-h) 0 0 0;z-index:1}
336
+ section[data-route]{display:none;position:absolute;inset:0}
337
+ section[data-route].active{display:block;animation:fade .5s var(--ease)}
338
+ @keyframes fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
339
+
340
+ /* a scrolling content column used by the doc-style sections */
341
+ .scroller{height:100%;overflow-y:auto}
342
+ .wrap{max-width:1180px;margin:0 auto;padding:46px 28px 120px}
343
+ .wrap.narrow{max-width:860px}
344
+
345
+ /* ─── shared typographic bits ─── */
346
+ .eyebrow{font-size:12.5px;font-weight:600;letter-spacing:.22em;text-transform:uppercase;color:var(--dim);margin-bottom:14px}
347
+ h1.title{font-size:clamp(38px,5.4vw,68px);font-weight:700;letter-spacing:-.032em;line-height:1.02}
348
+ .lead{font-size:clamp(15px,1.4vw,19px);line-height:1.55;color:var(--dim);max-width:66ch;margin-top:18px}
349
+ .lead strong{color:var(--ink);font-weight:600}
350
+ h2{font-size:clamp(26px,3.6vw,46px);font-weight:700;letter-spacing:-.026em;line-height:1.06}
351
+ h2 .soft{color:var(--dimmer)}
352
+ h3.kicker{font-size:12.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);margin-bottom:14px}
353
+
354
+ /* ─── reveals ─── */
355
+ [data-reveal]{opacity:0;transform:translateY(22px);
356
+ transition:opacity .8s var(--ease),transform .8s var(--ease);transition-delay:calc(var(--d,0)*1ms)}
357
+ .lit [data-reveal]{opacity:1;transform:none}
358
+ @media (prefers-reduced-motion:reduce){
359
+ [data-reveal]{transition:none;opacity:1;transform:none}
360
+ *{scroll-behavior:auto}
361
+ /* Ambient/decorative infinite-loop animations: shimmer
362
+ skeleton sweep, download-pulse dot, streaming cursor blink, running-
363
+ tool status dot. These loop forever by design and carry no state —
364
+ freezing them (not hiding) keeps the element visible+legible without
365
+ motion. One-shot transitions (fade-in on route change, toast slide-in,
366
+ popover open) are left alone; they're brief and convey state change,
367
+ not ambient decoration. */
368
+ #nav-download .dot,.shimmer,.cursor,.tool.running .sdot{animation:none!important}
369
+ .shimmer{color:inherit!important;background:var(--card)}
370
+ }
371
+
372
+ /* ─── cards ─── */
373
+ .grid{display:grid;gap:14px}
374
+ .g4{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
375
+ .card{background:var(--card);border:1px solid var(--hairline);border-radius:20px;
376
+ padding:24px 26px;transition:background .3s var(--ease),border-color .3s var(--ease)}
377
+ .card:hover{background:var(--card-hover)}
378
+ .card h3{font-size:12.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);margin-bottom:14px}
379
+ .stat{font-size:clamp(28px,3.2vw,42px);font-weight:700;letter-spacing:-.025em;line-height:1.05}
380
+ .stat small{font-size:.42em;font-weight:600;color:var(--dim);letter-spacing:0;margin-left:6px}
381
+ .card .cap{margin-top:8px;font-size:13.5px;color:var(--dim);line-height:1.5}
382
+ .kv{display:flex;justify-content:space-between;gap:10px;padding:5px 0;font-size:14.5px;border-bottom:1px solid var(--hairline-soft)}
383
+ .kv:last-child{border-bottom:none}
384
+ .kv b{font-weight:500;color:var(--dim)}
385
+ .kv span{font-weight:600}
386
+ .meter{height:5px;border-radius:3px;background:rgba(255,255,255,.09);margin-top:16px;overflow:hidden}
387
+ .meter i{display:block;height:100%;border-radius:3px;width:0%;
388
+ background:linear-gradient(90deg,var(--cyan),var(--blue));transition:width .8s var(--ease)}
389
+ .meter.warm i{background:linear-gradient(90deg,var(--orange),var(--pink))}
390
+ .meter.green i{background:linear-gradient(90deg,#a8ff9e,var(--green))}
391
+
392
+ /* ─── tables ─── */
393
+ table{width:100%;border-collapse:collapse;font-size:14.5px}
394
+ th,td{text-align:right;padding:13px 16px;border-bottom:1px solid var(--hairline-soft)}
395
+ th:first-child,td:first-child{text-align:left}
396
+ td:not(:first-child),th:not(:first-child){white-space:nowrap}
397
+ th{font-size:11.5px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:var(--dim)}
398
+ tr:last-child td{border-bottom:none}
399
+ tbody tr{transition:background .2s}
400
+ tbody tr:hover{background:rgba(255,255,255,.04)}
401
+ td.fit-yes{color:var(--green);font-weight:600}
402
+ td.fit-no{color:var(--dimmer)}
403
+ tr.you td{background:rgba(10,132,255,.10)}
404
+ tr.you td:first-child{border-left:3px solid var(--blue);border-radius:2px}
405
+ .tablecard{padding:8px 6px}
406
+
407
+ /* ─── forms (used by all three wizards) ─── */
408
+ .field{margin-bottom:18px}
409
+ .field>label{display:block;font-size:13px;font-weight:600;color:var(--ink);margin-bottom:8px;letter-spacing:-.01em}
410
+ .field .hint{font-size:12.5px;color:var(--dim);margin-top:7px;line-height:1.5}
411
+ input[type=text],input[type=number],input[type=password],textarea,select{
412
+ width:100%;background:var(--card);border:1px solid var(--hairline);border-radius:12px;
413
+ color:var(--ink);font:14.5px/1.5 inherit;padding:11px 14px;outline:none;
414
+ transition:border-color .22s var(--ease),background .22s var(--ease)}
415
+ input::placeholder,textarea::placeholder{color:var(--dimmer)}
416
+ input:focus,textarea:focus,select:focus{border-color:rgba(10,132,255,.55);background:var(--card-hover)}
417
+ textarea{resize:vertical;min-height:96px;font-family:var(--mono);font-size:13px}
418
+ select{appearance:none;-webkit-appearance:none;cursor:pointer;
419
+ background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2386868b' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
420
+ background-repeat:no-repeat;background-position:right 14px center;padding-right:34px}
421
+ .hpgrid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
422
+ .hpgrid .field{margin-bottom:0}
423
+ input[type=range]{width:100%;accent-color:var(--blue);background:transparent;cursor:pointer;height:24px}
424
+
425
+ /* segmented control */
426
+ .seg{display:inline-flex;background:var(--card);border:1px solid var(--hairline);border-radius:12px;padding:3px;gap:3px}
427
+ .seg button{appearance:none;background:none;border:none;cursor:pointer;color:var(--dim);
428
+ font:600 13.5px/1 inherit;padding:9px 18px;border-radius:9px;transition:all .22s var(--ease)}
429
+ .seg button.on{background:rgba(255,255,255,.12);color:var(--ink)}
430
+ .seg button:hover:not(.on){color:var(--ink)}
431
+
432
+ /* buttons */
433
+ .btn{appearance:none;border:none;cursor:pointer;font:600 14px/1 inherit;border-radius:13px;
434
+ padding:0 22px;height:46px;display:inline-flex;align-items:center;justify-content:center;gap:8px;
435
+ transition:filter .2s,opacity .2s,background .22s var(--ease)}
436
+ .btn.primary{background:linear-gradient(120deg,var(--blue),var(--purple));color:#fff}
437
+ .btn.primary:hover{filter:brightness(1.13)}
438
+ .btn.ghost{background:var(--card);border:1px solid var(--hairline);color:var(--ink)}
439
+ .btn.ghost:hover{background:var(--card-hover)}
440
+ .btn:disabled{filter:grayscale(.7) brightness(.55);cursor:default;opacity:.7}
441
+ .btn.sm{height:38px;padding:0 16px;font-size:13px;border-radius:11px}
442
+ .btnrow{display:flex;gap:10px;margin-top:24px;flex-wrap:wrap;align-items:center}
443
+
444
+ /* flash / status banners */
445
+ .flash{border-radius:14px;padding:13px 16px;font-size:14px;line-height:1.5;border:1px solid;margin-top:14px}
446
+ .flash.ok{background:rgba(48,209,88,.10);border-color:rgba(48,209,88,.35);color:#b8f5c4}
447
+ .flash.warn{background:rgba(255,159,10,.10);border-color:rgba(255,159,10,.35);color:#ffe0a8}
448
+ .flash.err{background:rgba(255,69,58,.10);border-color:rgba(255,69,58,.35);color:#ffb8b3}
449
+ .flash code{background:rgba(0,0,0,.3)}
450
+ .flash strong{color:var(--ink)}
451
+
452
+ .soon{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;letter-spacing:.06em;
453
+ text-transform:uppercase;color:var(--dimmer);border:1px solid var(--hairline-soft);border-radius:999px;padding:3px 10px}
454
+
455
+ /* step indicator */
456
+ .steps{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 30px;font:600 12px var(--mono);
457
+ text-transform:uppercase;letter-spacing:.05em;color:var(--dimmer)}
458
+ .steps .s{display:inline-flex;align-items:center;gap:8px}
459
+ .steps .s .n{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;
460
+ border:1px solid var(--hairline);font-size:11px;color:var(--dim);transition:all .3s var(--ease)}
461
+ .steps .s.done .n{background:rgba(255,255,255,.10);color:var(--ink);border-color:transparent}
462
+ .steps .s.cur .n{background:linear-gradient(120deg,var(--blue),var(--purple));color:#fff;border-color:transparent}
463
+ .steps .s.cur{color:var(--ink)}
464
+ .steps .s.done{color:var(--dim)}
465
+ .steps .arrow{color:var(--dimmer);margin:0 2px}
466
+
467
+ /* progress + log shared by every job stream */
468
+ .progressbar{height:8px;background:rgba(255,255,255,.09);border-radius:5px;overflow:hidden}
469
+ .progressbar i{display:block;height:100%;width:0%;border-radius:5px;
470
+ background:linear-gradient(90deg,var(--cyan),var(--blue));transition:width .5s var(--ease)}
471
+ .progressbar.green i{background:linear-gradient(90deg,#a8ff9e,var(--green))}
472
+ .progmeta{display:flex;justify-content:space-between;font-size:12.5px;color:var(--dim);margin-top:8px}
473
+ .logbox{margin-top:18px;background:var(--code-bg-soft);border:1px solid var(--hairline-soft);border-radius:14px;
474
+ padding:14px 16px;max-height:340px;overflow-y:auto;font:11.5px/1.55 var(--mono);color:rgba(245,245,247,.7);white-space:pre-wrap;word-break:break-word}
475
+ .logbox:empty::before{content:"waiting for output…";color:var(--dimmer)}
476
+
477
+ /* shimmer skeletons */
478
+ .shimmer{background:linear-gradient(100deg,rgba(255,255,255,.04) 30%,rgba(255,255,255,.10) 50%,rgba(255,255,255,.04) 70%);
479
+ background-size:200% 100%;animation:sh 1.4s ease-in-out infinite;border-radius:8px;color:transparent!important}
480
+ @keyframes sh{0%{background-position:200% 0}100%{background-position:-200% 0}}
481
+
482
+ /* toasts */
483
+ #toasts{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:100;
484
+ display:flex;flex-direction:column;gap:10px;align-items:center;pointer-events:none}
485
+ .toast{background:var(--overlay-panel);backdrop-filter:blur(20px);border:1px solid var(--hairline);
486
+ border-radius:13px;padding:12px 18px;font-size:14px;font-weight:500;box-shadow:0 16px 50px rgba(0,0,0,.35);
487
+ animation:toastIn .4s var(--ease);max-width:min(560px,90vw)}
488
+ .toast.err{border-color:rgba(255,69,58,.5)}
489
+ .toast.ok{border-color:rgba(48,209,88,.5)}
490
+ @keyframes toastIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
491
+
492
+
493
+
494
+
495
+
496
+ /* empty state */
497
+ .empty{text-align:center;color:var(--dim);padding:60px 20px}
498
+ .empty h3{font-size:18px;font-weight:600;color:var(--ink);margin-bottom:8px;letter-spacing:-.01em}
499
+ .empty p{font-size:14px;max-width:46ch;margin:0 auto}
500
+
501
+
502
+
503
+
504
+
505
+
506
+
507
+
508
+
509
+
510
+
511
+
512
+
513
+
514
+
515
+
516
+
517
+
518
+
519
+ #chat-hamburger{display:none}
520
+ @media (max-width:760px){
521
+ #chat-hamburger{display:inline-flex}
522
+ }
523
+
524
+
525
+
526
+
527
+
528
+
529
+
530
+
531
+
532
+
533
+
534
+
535
+
536
+
537
+
538
+
539
+
540
+
541
+
542
+
543
+ /* markdown-ish rendering — shared by chat bubbles AND the memory panel's
544
+ article view (.mem-article-render renders vault/Reference docs through
545
+ the same mdToHtml; without this scope the panel's code fences lost
546
+ their header chrome — "shCopy" mash, 2026-07-07 visual QA). */
547
+ :is(.bubble,.mem-article-render) p{margin:0 0 10px}:is(.bubble,.mem-article-render) p:last-child{margin-bottom:0}
548
+ :is(.bubble,.mem-article-render) ul,:is(.bubble,.mem-article-render) ol{margin:0 0 10px;padding-left:22px}
549
+ :is(.bubble,.mem-article-render) li{margin:3px 0}
550
+ :is(.bubble,.mem-article-render) strong{font-weight:700;color:var(--ink)}
551
+ :is(.bubble,.mem-article-render) em{font-style:italic}
552
+ :is(.bubble,.mem-article-render) code{font-family:var(--mono);font-size:.86em;background:rgba(127,127,127,.18);padding:2px 7px;border-radius:6px}
553
+ :is(.bubble,.mem-article-render) pre{background:var(--code-bg);color:var(--code-ink);border:1px solid var(--hairline-soft);border-radius:12px;
554
+ padding:13px 15px;overflow-x:auto;margin:10px 0;font:12.5px/1.6 var(--mono)}
555
+ :is(.bubble,.mem-article-render) pre code{background:none;padding:0;font-size:inherit;color:inherit}
556
+ :is(.bubble,.mem-article-render) h1,:is(.bubble,.mem-article-render) h2,:is(.bubble,.mem-article-render) h3,:is(.bubble,.mem-article-render) h4,:is(.bubble,.mem-article-render) h5,:is(.bubble,.mem-article-render) h6{font-weight:700;margin:14px 0 7px;letter-spacing:-.01em;line-height:1.3}
557
+ :is(.bubble,.mem-article-render) h1{font-size:1.28em}:is(.bubble,.mem-article-render) h2{font-size:1.16em}:is(.bubble,.mem-article-render) h3{font-size:1.06em}
558
+ :is(.bubble,.mem-article-render) h4,:is(.bubble,.mem-article-render) h5,:is(.bubble,.mem-article-render) h6{font-size:1em;color:var(--dim)}
559
+ :is(.bubble,.mem-article-render) h1:first-child,:is(.bubble,.mem-article-render) h2:first-child,:is(.bubble,.mem-article-render) h3:first-child{margin-top:0}
560
+ :is(.bubble,.mem-article-render) a{color:var(--cyan);text-decoration:none;border-bottom:1px solid rgba(100,210,255,.34)}
561
+ :is(.bubble,.mem-article-render) a:hover{border-bottom-color:var(--cyan)}
562
+ :is(.bubble,.mem-article-render) del{opacity:.55}
563
+ :is(.bubble,.mem-article-render) blockquote{margin:9px 0;padding:3px 14px;border-left:3px solid var(--hairline);color:var(--dim)}
564
+ :is(.bubble,.mem-article-render) blockquote p:last-child{margin-bottom:0}
565
+ :is(.bubble,.mem-article-render) hr{border:none;border-top:1px solid var(--hairline);margin:15px 0}
566
+ :is(.bubble,.mem-article-render) li.task{list-style:none;margin-left:-18px}
567
+ :is(.bubble,.mem-article-render) li.task input{margin-right:7px;accent-color:var(--blue);vertical-align:-1px}
568
+ :is(.bubble,.mem-article-render) .md-tablewrap{overflow-x:auto;margin:11px 0}
569
+ :is(.bubble,.mem-article-render) table.md-table{width:100%;border-collapse:collapse;font-size:.92em}
570
+ :is(.bubble,.mem-article-render) table.md-table th,:is(.bubble,.mem-article-render) table.md-table td{border:1px solid var(--hairline-soft);padding:6px 11px;text-align:left}
571
+ :is(.bubble,.mem-article-render) table.md-table th{background:rgba(255,255,255,.05);font-weight:600;color:var(--ink)}
572
+ :is(.bubble,.mem-article-render) .codeblock{margin:11px 0;border:1px solid var(--hairline-soft);border-radius:12px;overflow:hidden;background:var(--code-bg);color:var(--code-ink)}
573
+ :is(.bubble,.mem-article-render) .cbhead{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:5px 9px 5px 13px;background:rgba(255,255,255,.04);border-bottom:1px solid var(--hairline-soft)}
574
+ :is(.bubble,.mem-article-render) .cblang{font:11px/1 var(--mono);color:rgba(245,245,247,.65);letter-spacing:.02em}
575
+ :is(.bubble,.mem-article-render) .cbcopy{font:11px/1 var(--mono);color:rgba(245,245,247,.65);background:transparent;border:1px solid rgba(255,255,255,.2);border-radius:6px;padding:4px 10px;cursor:pointer;transition:color .15s,border-color .15s}
576
+ :is(.bubble,.mem-article-render) .cbcopy:hover{color:var(--code-ink);border-color:rgba(255,255,255,.4)}
577
+ :is(.bubble,.mem-article-render) .codeblock pre{margin:0;border:none;border-radius:0;background:transparent;color:inherit}
578
+ /* Canvas v1 (`02d723a:docs/design/web-chat-redesign.md` Appendix A,
579
+ beat-matrix Axis 2): Preview|Source toggle
580
+ for html/svg fences, sharing .cbhead with the existing lang tag + Copy
581
+ button. .cbhead keeps lang pinned left; the toggle+copy group sits
582
+ right via margin-left:auto on the first right-side element instead of
583
+ space-between, since space-between with 3 children would push the
584
+ toggle to the dead center of the bar. */
585
+ :is(.bubble,.mem-article-render) .cbhead{justify-content:flex-start}
586
+ :is(.bubble,.mem-article-render) .cbtoggle{display:inline-flex;gap:2px;margin-left:auto;padding:2px;border-radius:7px;background:rgba(255,255,255,.05)}
587
+ :is(.bubble,.mem-article-render) .cbview{font:11px/1 var(--mono);color:rgba(245,245,247,.55);background:transparent;border:none;
588
+ border-radius:5px;padding:4px 9px;cursor:pointer;transition:color .15s,background .15s}
589
+ :is(.bubble,.mem-article-render) .cbview:hover{color:var(--code-ink)}
590
+ :is(.bubble,.mem-article-render) .cbview.active{color:var(--code-ink);background:rgba(255,255,255,.14)}
591
+ /* has-canvas keeps Copy visually last, right after the toggle group. */
592
+ :is(.bubble,.mem-article-render) .codeblock.has-canvas .cbcopy{margin-left:2px}
593
+ :is(.bubble,.mem-article-render) .cbcanvas{position:relative;background:#fff}
594
+ :is(.bubble,.mem-article-render) .cbframe{display:block;width:100%;height:420px;min-height:160px;max-height:80vh;
595
+ border:none;resize:vertical;overflow:auto;background:#fff}
596
+ /* No layout shift on toggle: pre and cbcanvas are simply swapped via
597
+ [hidden] — the codeblock's own border/rounding stays put, and the
598
+ iframe's own default height (420px) plus resize:vertical means the
599
+ block doesn't jump when Preview first opens vs. later re-opens. */
600
+
601
+
602
+
603
+
604
+
605
+
606
+
607
+
608
+
609
+
610
+
611
+
612
+
613
+
614
+
615
+
616
+
617
+
618
+
619
+
620
+
621
+
622
+
623
+
624
+
625
+
626
+
627
+
628
+
629
+
630
+
631
+
632
+
633
+
634
+
635
+
636
+
637
+
638
+
639
+
640
+
641
+
642
+
643
+
644
+
645
+
646
+
647
+
648
+
649
+
650
+
651
+
652
+
653
+
654
+
655
+
656
+
657
+
658
+
659
+
660
+
661
+
662
+
663
+
664
+
665
+
666
+
667
+
668
+
669
+
670
+
671
+
672
+
673
+
674
+
675
+
676
+
677
+
678
+
679
+
680
+
681
+
682
+
683
+
684
+
685
+
686
+
687
+
688
+
689
+
690
+
691
+
692
+
693
+ /* loss chart */
694
+ .chartcard{margin-top:20px}
695
+ /* the chart's SVG gridlines are hardcoded white-on-dark (drawChart()), so
696
+ the wrap keeps the always-dark code-panel surface for contrast rather
697
+ than following the chat theme — same rationale as .bubble pre above. */
698
+ .chart-wrap{position:relative;background:var(--code-bg-soft);border:1px solid var(--hairline-soft);border-radius:14px;padding:14px;margin-top:6px}
699
+ .chart-legend{display:flex;gap:18px;font-size:12px;color:var(--dim);margin-bottom:8px}
700
+ .chart-legend .lg{display:inline-flex;align-items:center;gap:7px}
701
+ .chart-legend .sw{width:14px;height:3px;border-radius:2px}
702
+ .chart-stats{display:flex;gap:22px;flex-wrap:wrap;margin-top:12px;font-size:13px}
703
+ .chart-stats .cs b{display:block;font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);margin-bottom:3px}
704
+ .chart-stats .cs span{font-size:20px;font-weight:700;letter-spacing:-.02em}
705
+
706
+ /* Tablet band (2026-07-06 jank fix): with up to 7 tabs (fewer once the
707
+ Developer toggle is off — see nav .tab[data-dev] above) +
708
+ hamburger + shortcuts + theme toggle + gear + conn pill, the tab row
709
+ can overflow well above the 900px cutoff — tighten tab padding first
710
+ so fewer widths need the scroll-fade at all. */
711
+ @media (max-width:1160px){
712
+ nav{gap:12px}
713
+ nav .tab{padding:8px 9px;font-size:13px}
714
+ }
715
+ @media (max-width:900px){
716
+ .hpgrid{grid-template-columns:1fr}
717
+ nav .model{display:none}
718
+ .wrap{padding:34px 18px 100px}
719
+ nav{gap:12px;padding:0 16px}
720
+ /* Icon-only theme toggle a bit earlier than 560px — the nav is already
721
+ tight here (hamburger + shortcuts + toggle + hf-gear + conn pill) and
722
+ "Auto" as a text label isn't worth the horizontal cost at this width.
723
+ The ◐ tt-icon stands in so the Auto button never renders as an empty
724
+ sliver (2026-07-06 QA finding). */
725
+ #theme-toggle button{padding:0 7px;font-size:15px}
726
+ #theme-toggle .tt-label{display:none}
727
+ #theme-toggle .tt-icon{display:inline}
728
+ /* Developer toggle: dot-only past this width, same reasoning as the
729
+ theme toggle above — "Developer" as a text label costs more than
730
+ the dot alone conveys once the row is already tight. */
731
+ #nav-developer span:not(.nd-dot){display:none}
732
+ #nav-developer{padding:0;width:34px;justify-content:center}
733
+ }
734
+ @media (max-width:760px){
735
+ /* Touch band (2026-07-06 QA): a keyboard-shortcut sheet button is dead
736
+ weight on touch viewports, and the nav needs its width back. */
737
+ #nav-shortcuts{display:none}
738
+ /* The conn pill collapses to its status dot (title keeps the text for
739
+ long-press/hover); "live · localhost" was clipping at the viewport
740
+ edge at 375px. */
741
+ #nav-conn #nav-conn-text{display:none}
742
+ #nav-conn{padding:6px 9px}
743
+ /* Keep a scrollable strip of tabs alive — flex shrank them to 0 width
744
+ at phone sizes, silently removing Quantize/Status navigation. The
745
+ scroll-fade masks signal the rest. With the Developer toggle off
746
+ (the fresh-browser default) this row can be just the single Chat
747
+ tab — min-width still holds so the fade-mask math in
748
+ updateTabFades() never divides against a zero-width strip. */
749
+ nav .tabs{min-width:96px}
750
+ }
751
+ @media (max-width:560px){
752
+ nav .brand{font-size:16px}
753
+ nav .tab{padding:8px 10px;font-size:13px}
754
+ nav .right{gap:6px}
755
+ .icon-btn,.hf-gear{width:30px;height:30px}
756
+ /* Phones follow the system theme (Auto is the default); the explicit
757
+ 3-way toggle returns ≥560px. Freeing its ~110px is what keeps the
758
+ tab strip + status dot inside a 375px viewport (2026-07-06 QA). */
759
+ #theme-toggle{display:none}
760
+ }
761
+ </style>
762
+ <!-- Vendored syntax-highlighting theme (apps/mlx-bun/src/web/public/vendor/hljs-theme.css,
763
+ hand-derived from the design tokens above — see that file's header). No CDN;
764
+ served by apps/mlx-bun/src/web/assets.ts alongside this page. -->
765
+ <link rel="stylesheet" href="/assets/hljs.css">
766
+ <!-- PWA installability (`02d723a:docs/design/web-chat-redesign.md` Appendix A,
767
+ beat-matrix Axis 10): manifest +
768
+ inline SVG icon (apps/mlx-bun/src/web/public/manifest.webmanifest,
769
+ apps/mlx-bun/src/web/public/icon.svg — no binary PNGs, per the hygiene gate;
770
+ some browsers won't render an SVG app icon and that's an accepted tradeoff).
771
+ theme-color matches the app's --bg token so the OS chrome doesn't
772
+ flash a mismatched color on launch. -->
773
+ <link rel="manifest" href="/manifest.webmanifest">
774
+ <link rel="icon" href="/assets/icon.svg" type="image/svg+xml">
775
+ <link rel="apple-touch-icon" href="/assets/icon.svg">
776
+ <meta name="theme-color" content="#000000">
777
+ </head>
778
+ <body>
779
+ <div class="bloom" id="bloom"></div>
780
+
781
+ <!-- ═══════════════════ TOP NAV ═══════════════════ -->
782
+ <nav>
783
+ <!-- Mobile drawer trigger — chat route only (CSS keeps it hidden ≥760px
784
+ and JS keeps it hidden off the chat route, since there is no
785
+ sidebar to open elsewhere). aria-controls/expanded kept in sync by
786
+ the drawer open/close functions. -->
787
+ <button class="icon-btn" id="chat-hamburger" title="Open recent chats" aria-label="Open recent chats"
788
+ aria-controls="chat-sidebar" aria-expanded="false">
789
+ <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
790
+ </button>
791
+ <a class="brand grad g-hero" href="#/chat">mlx-bun</a>
792
+ <div class="tabs" id="tabs">
793
+ <a class="tab" href="#/status" data-tab="status" data-dev>Status</a>
794
+ <a class="tab" href="#/routes" data-tab="routes" data-dev>Routes</a>
795
+ </div>
796
+ <div class="right">
797
+ <!-- Developer toggle: collapses Quantize/Fine-tune/
798
+ Build Dataset/Status/Curves/Routes behind one switch. State + the
799
+ one-time existing-user default live in shell.ts's
800
+ initDeveloperToggle/isDeveloperMode. -->
801
+ <button id="nav-developer" data-spotlight="developer-toggle" type="button" role="switch" aria-checked="false"
802
+ title="Show developer tools (Quantize, Fine-tune, Build Dataset, Status, Curves, Routes)"
803
+ aria-label="Toggle developer tools">
804
+ <span class="nd-dot" id="nav-developer-dot" aria-hidden="true"></span><span>Developer</span>
805
+ </button>
806
+ <button class="icon-btn" id="nav-shortcuts" title="Keyboard shortcuts (Cmd/Ctrl+/)" aria-label="Keyboard shortcuts"
807
+ aria-haspopup="dialog" aria-controls="shortcut-overlay" aria-expanded="false">
808
+ <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="6" width="20" height="12" rx="2"></rect><path d="M6 10h.01M10 10h.01M14 10h.01M18 10h.01M6 14h12"></path></svg>
809
+ </button>
810
+ <!-- 3-way theme toggle: auto follows prefers-color-scheme,
811
+ dark/light are explicit user overrides — all persisted to
812
+ localStorage by setTheme() below. -->
813
+ <div id="theme-toggle" role="group" aria-label="Theme">
814
+ <button type="button" data-theme-choice="auto" title="Match system theme" aria-label="Auto theme"><span class="tt-icon" aria-hidden="true">◐</span><span class="tt-label">Auto</span></button>
815
+ <button type="button" data-theme-choice="dark" title="Dark theme" aria-label="Dark theme">🌙</button>
816
+ <button type="button" data-theme-choice="light" title="Light theme" aria-label="Light theme">☀️</button>
817
+ </div>
818
+ <button class="hf-gear" id="nav-hf" title="Hugging Face token settings" aria-label="Hugging Face settings">
819
+ <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
820
+ </button>
821
+ <!-- The active model; clicking it opens the Models page (the models module's panel). -->
822
+ <button class="model" id="nav-model" data-spotlight="model-picker" type="button" title="active model — click to manage models">connecting…</button>
823
+ <span class="pill" id="nav-conn"><span class="dot"></span><span id="nav-conn-text">connecting…</span></span>
824
+ <span class="pill" id="nav-download" style="display:none" title="A more capable model is downloading in the background"><span class="dot"></span><span id="nav-download-text"></span></span>
825
+ </div>
826
+ </nav>
827
+
828
+ <!-- ═══════════════════ SETTINGS OVERLAY ═══════════════════
829
+ (was "HF settings" — widened in place for the Agent tools section.
830
+ Same ids/behavior for the HF piece; nothing
831
+ about push-to-hub or the hf-* wiring changed.) -->
832
+ <div id="hf-overlay">
833
+ <div id="hf-modal" role="dialog" aria-modal="true" aria-labelledby="hf-modal-title-el">
834
+ <div class="hf-modal-head">
835
+ <div class="hf-modal-title" id="hf-modal-title-el">Settings</div>
836
+ <button class="hf-close" id="hf-close" aria-label="Close">✕</button>
837
+ </div>
838
+
839
+ <!-- Agent tools: the codingTools opt-in + the durable
840
+ always-allow list. Lives above Hugging Face since it's the more
841
+ chat-relevant setting. -->
842
+ <div class="settings-section">
843
+ <h3 class="settings-h">Agent tools</h3>
844
+ <label class="chk settings-toggle-row" for="settings-coding-tools">
845
+ <input type="checkbox" id="settings-coding-tools">
846
+ <span>Let the agent touch files on this machine</span>
847
+ </label>
848
+ <div class="hint">
849
+ Off by default. When on, the chat assistant can run shell commands and
850
+ edit or create files — each one asks first, in the chat, unless you
851
+ choose "always allow" for that action. Nothing runs without your
852
+ review the first time.
853
+ </div>
854
+ <p class="settings-note" id="settings-coding-tools-note" style="display:none"></p>
855
+ <div id="settings-approvals-list"></div>
856
+ </div>
857
+
858
+ <div class="settings-section">
859
+ <h3 class="settings-h">Hugging Face</h3>
860
+ <p class="hf-modal-sub" id="hf-state">Checking for a saved token…</p>
861
+ <div class="field" style="margin-bottom:10px">
862
+ <label>Write token</label>
863
+ <input type="password" id="hf-token-input" placeholder="hf_…" autocomplete="off" spellcheck="false">
864
+ <div class="hint">A <strong>write</strong> token from huggingface.co/settings/tokens. Stored locally at <code>~/.mlx-bun/hf.json</code> — never sent anywhere but your own Hub pushes.</div>
865
+ </div>
866
+ <div id="hf-settings-msg"></div>
867
+ <div class="btnrow" style="margin-top:14px">
868
+ <button class="btn primary sm" id="hf-save">Save token</button>
869
+ </div>
870
+ </div>
871
+ </div>
872
+ </div>
873
+
874
+ <!-- ═══════════════════ KEYBOARD SHORTCUT SHEET ═══════════════════ -->
875
+ <div id="shortcut-overlay">
876
+ <div id="shortcut-modal" role="dialog" aria-modal="true" aria-labelledby="sk-modal-title">
877
+ <div class="sk-head">
878
+ <div class="sk-title" id="sk-modal-title">Keyboard shortcuts</div>
879
+ <button class="sk-close" id="sk-close" aria-label="Close">✕</button>
880
+ </div>
881
+ <div class="sk-row"><span class="sk-desc">Show this shortcut sheet</span><span class="sk-keys"><span class="sk-key" id="sk-mod-label">⌘</span><span class="sk-key">/</span></span></div>
882
+ <div class="sk-row"><span class="sk-desc">New chat</span><span class="sk-keys"><span class="sk-key sk-mod"></span><span class="sk-key">Shift</span><span class="sk-key">O</span></span></div>
883
+ <div class="sk-row"><span class="sk-desc">Focus the composer</span><span class="sk-keys"><span class="sk-key">Shift</span><span class="sk-key">Esc</span></span></div>
884
+ <div class="sk-row"><span class="sk-desc">Copy last response</span><span class="sk-keys"><span class="sk-key sk-mod"></span><span class="sk-key">Shift</span><span class="sk-key">C</span></span></div>
885
+ <div class="sk-row"><span class="sk-desc">Send message</span><span class="sk-keys"><span class="sk-key">Enter</span></span></div>
886
+ <div class="sk-row"><span class="sk-desc">New line in composer</span><span class="sk-keys"><span class="sk-key">Shift</span><span class="sk-key">Enter</span></span></div>
887
+ <div class="sk-row"><span class="sk-desc">Close popover / drawer / sheet</span><span class="sk-keys"><span class="sk-key">Esc</span></span></div>
888
+ </div>
889
+ </div>
890
+
891
+ <!-- The chat is the module panel (`@mlx-bun/module-chat`): the shell mounts it as the first page. -->
892
+
893
+ <div id="app">
894
+
895
+ <!-- The chat workspace panel is mounted by the shell. -->
896
+
897
+ <!-- ═══════════════════ QUANTIZE ═══════════════════ -->
898
+
899
+ <!-- ═══════════════════ FINE-TUNE ═══════════════════ -->
900
+
901
+ <!-- ═══════════════════ DATASET ═══════════════════ -->
902
+
903
+ <!-- ═══════════════════ STATUS ═══════════════════ -->
904
+ <section data-route="status" id="s-status">
905
+ <div class="scroller"><div class="wrap" id="status-page">
906
+
907
+ <div style="text-align:center;margin-bottom:18px" data-reveal>
908
+ <div class="eyebrow" style="margin-bottom:18px">local ai · apple silicon · one binary</div>
909
+ <h1 class="title grad g-hero" style="font-size:clamp(48px,8vw,110px)">mlx-bun</h1>
910
+ <p class="lead" style="margin:18px auto 0;text-align:center">The Python-free local AI engine. <strong>Bun + MLX, nothing else.</strong></p>
911
+ </div>
912
+
913
+ <section style="margin-top:56px" data-reveal>
914
+ <h2>Now serving<span class="soft">.</span></h2>
915
+ <div class="grid g4" style="margin-top:24px">
916
+ <div class="card" id="st-model-card" style="grid-column:1 / -1;display:flex;flex-wrap:wrap;align-items:baseline;gap:14px 26px">
917
+ <div><h3>Model</h3><div id="st-model-id" style="font-size:clamp(20px,2.6vw,32px);font-weight:700;letter-spacing:-.02em;word-break:break-all">—</div></div>
918
+ <div id="st-model-meta" style="font-size:14.5px;color:var(--dim);font-weight:500">—</div>
919
+ </div>
920
+ <div class="card">
921
+ <h3>Decode · predicted</h3>
922
+ <div class="stat num grad g-green"><span id="st-tps">—</span><small>tok/s</small></div>
923
+ <div class="cap" id="st-tps-cap">from weights ÷ bandwidth on this machine</div>
924
+ </div>
925
+ <div class="card">
926
+ <h3>Max safe context</h3>
927
+ <div class="stat num grad g-blue"><span id="st-safe-ctx">—</span><small>tokens</small></div>
928
+ <div class="cap">solved from KV growth + prefill transient, never guessed</div>
929
+ </div>
930
+ <div class="card">
931
+ <h3>Memory</h3>
932
+ <div class="kv"><b>weights</b><span class="num" id="st-weights">—</span></div>
933
+ <div class="kv"><b>usable</b><span class="num" id="st-usable">—</span></div>
934
+ <div class="kv"><b>budget</b><span class="num" id="st-budget">—</span></div>
935
+ <div class="meter warm"><i id="st-mem-bar"></i></div>
936
+ </div>
937
+ <div class="card">
938
+ <h3>Prompt cache</h3>
939
+ <div class="kv"><b>hit rate</b><span class="num" id="st-pc-hits">—</span></div>
940
+ <div class="kv"><b>entries</b><span class="num" id="st-pc-entries">—</span></div>
941
+ <div class="kv"><b>bytes</b><span class="num" id="st-pc-bytes">—</span></div>
942
+ <div class="meter"><i id="st-pc-bar"></i></div>
943
+ </div>
944
+ <div class="card">
945
+ <h3>Response store</h3>
946
+ <div class="kv"><b>entries</b><span class="num" id="st-rs-entries">—</span></div>
947
+ <div class="kv"><b>bytes</b><span class="num" id="st-rs-bytes">—</span></div>
948
+ <div class="kv"><b>ttl</b><span class="num" id="st-rs-ttl">—</span></div>
949
+ <div class="meter"><i id="st-rs-bar"></i></div>
950
+ </div>
951
+ <div class="card">
952
+ <h3>KV quantization</h3>
953
+ <div class="kv"><b>mode</b><span id="st-kv-mode">—</span></div>
954
+ <div id="st-kv-layers"></div>
955
+ </div>
956
+ <div class="card" id="st-expert-card" style="display:none">
957
+ <h3>Expert tiers · last turn</h3>
958
+ <div class="kv"><b>main cache hit</b><span class="num" id="st-expert-main-hit">—</span></div>
959
+ <div class="kv"><b>main SSD read</b><span class="num" id="st-expert-main-read">—</span></div>
960
+ <div class="kv"><b>MTP cache hit</b><span class="num" id="st-expert-mtp-hit">—</span></div>
961
+ <div class="kv"><b>MTP SSD read</b><span class="num" id="st-expert-mtp-read">—</span></div>
962
+ <div class="cap" id="st-expert-residency">waiting for the first completed turn</div>
963
+ </div>
964
+ <div class="card" id="st-dl-card" style="grid-column:1 / -1;display:none">
965
+ <h3>Downloads</h3>
966
+ <div id="st-dl-list"></div>
967
+ </div>
968
+ </div>
969
+ </section>
970
+
971
+ <section style="margin-top:80px" data-reveal>
972
+ <h2>Library<span class="soft">.</span> <span class="grad g-green">Every model, assessed.</span></h2>
973
+ <p class="lead">Everything in the local cache, each judged by the fit solver for <strong>this machine</strong>.</p>
974
+ <div class="card tablecard" style="margin-top:26px">
975
+ <table>
976
+ <thead><tr><th>Model</th><th>Size</th><th>Status</th><th>Max context</th><th>Decode</th></tr></thead>
977
+ <tbody id="st-lib-body"><tr><td colspan="5" style="text-align:center;color:var(--dimmer)">waiting for server…</td></tr></tbody>
978
+ </table>
979
+ </div>
980
+ </section>
981
+
982
+ <section style="margin-top:80px" data-reveal>
983
+ <h2>Will it fit<span class="soft">?</span> <span class="grad g-blue">Solved, not guessed.</span></h2>
984
+ <p class="lead">Weights + KV growth + prefill transient against wired memory — the same assessment that gates every request.</p>
985
+ <div class="grid g4" style="margin:26px 0 14px">
986
+ <div class="card">
987
+ <h3>This machine</h3>
988
+ <div class="kv"><b>RAM</b><span class="num" id="st-m-ram">—</span></div>
989
+ <div class="kv"><b>bandwidth</b><span class="num" id="st-m-bw">—</span></div>
990
+ <div class="kv"><b>verdict</b><span id="st-m-fits">—</span></div>
991
+ </div>
992
+ <div class="card">
993
+ <h3>At max context · <span class="num" id="st-fit-ctx">—</span> tokens</h3>
994
+ <div class="kv" data-plan-fit style="display:none"><b>artifact on disk</b><span class="num" id="st-f-artifact">—</span></div>
995
+ <div class="kv"><b id="st-f-weights-label">weights</b><span class="num" id="st-f-weights">—</span></div>
996
+ <div id="st-f-streamed"></div>
997
+ <div class="kv"><b>kv cache</b><span class="num" id="st-f-kv">—</span></div>
998
+ <div class="kv"><b id="st-f-transient-label">transient</b><span class="num" id="st-f-transient">—</span></div>
999
+ <div class="kv"><b>total / usable</b><span class="num" id="st-f-total">—</span></div>
1000
+ <div class="meter"><i id="st-fit-bar"></i></div>
1001
+ </div>
1002
+ </div>
1003
+ <div class="card tablecard">
1004
+ <table>
1005
+ <thead><tr><th>Apple silicon · this model @ <span class="num" id="st-sku-ctx">32,768</span> ctx</th>
1006
+ <th>RAM</th><th>Fits</th><th>Max context</th><th>Decode</th></tr></thead>
1007
+ <tbody id="st-sku-body"><tr><td colspan="5" style="text-align:center;color:var(--dimmer)">waiting for server…</td></tr></tbody>
1008
+ </table>
1009
+ </div>
1010
+ </section>
1011
+
1012
+ <footer style="margin-top:90px;border-top:1px solid var(--hairline);padding-top:26px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:12px;font-size:13px;color:var(--dimmer)">
1013
+ <span>mlx-bun · M-series Macs · no Python anywhere in the serving path</span>
1014
+ <span>server up <span id="st-uptime">—</span> · updated <span id="st-updated">never</span></span>
1015
+ </footer>
1016
+ </div></div>
1017
+ </section>
1018
+
1019
+ <!-- ═══════════════════ ROUTES ═══════════════════ -->
1020
+ <!-- `02d723a:docs/archive/planning/web-ui-pass-plan.md` #17: /dag 404s outside a repo checkout (readFileSync
1021
+ on a repo-relative doc, absent from compiled binaries/npm installs).
1022
+ shell.ts's initRoutesProbe() HEAD-checks /dag at boot: on success this
1023
+ iframe renders as-is; on 404 it hides the Routes tab and swaps this
1024
+ section's innerHTML for a graceful note instead of a raw 404 iframe.
1025
+ Could instead embed the artifact server-side like /curves' fallback
1026
+ does. -->
1027
+ <section data-route="routes" id="s-routes">
1028
+ <iframe src="/dag" title="Training · inference route map"
1029
+ style="width:100%;height:100%;border:0;display:block"></iframe>
1030
+ </section>
1031
+
1032
+ </div>
1033
+
1034
+ <div id="toasts"></div>
1035
+
1036
+ <!-- Vendored syntax highlighter (apps/mlx-bun/src/web/public/vendor/hljs.js — highlight.js core +
1037
+ a curated language set, BSD-3-Clause, see that file's header). `defer`
1038
+ means this loads/executes at DOMContentLoaded, which happens well before
1039
+ any real highlighting call (those only fire later, on streamed content
1040
+ or history replay) — app.js (below) only *calls* highlightIn() from
1041
+ async event handlers, so load order here is safe in practice.
1042
+ highlightIn() still guards with `typeof hljs !== "undefined"` for the
1043
+ case this tag is ever stripped or the asset 404s. No CDN; served by
1044
+ apps/mlx-bun/src/web/assets.ts at /assets/hljs.js. -->
1045
+ <script defer src="/assets/hljs.js"></script>
1046
+ <!-- The app itself: GENERATED bundle of the src/web/browser/*.ts
1047
+ module split, built by `bun run --filter mlx-bun build:web` into dist/web/app.js
1048
+ and served by apps/mlx-bun/src/web/assets.ts at /assets/app.js — see that file's header
1049
+ comment. `defer` (like hljs.js above) means both scripts run in document
1050
+ order at DOMContentLoaded, after the DOM this script queries with $()
1051
+ is fully parsed. Edit src/web/browser/*.ts, never this bundle or this tag. -->
1052
+ <script defer src="/assets/app.js"></script>
1053
+ </body>
1054
+ </html>