mlx-bun 0.5.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 (640) hide show
  1. package/README.md +1449 -109
  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 +7 -5
  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 +10 -10
  78. package/src/{serve → server}/chat-stage.ts +14 -14
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +33 -41
  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 +25 -82
  85. package/src/{serve → server}/http.ts +25 -13
  86. package/src/{serve → server}/inference-request.ts +5 -5
  87. package/src/server/job-routes.ts +20 -0
  88. package/src/server/media-prompt.ts +63 -0
  89. package/src/server/memory-completion-client.ts +46 -0
  90. package/src/server/model-routes.ts +192 -0
  91. package/src/{serve → server}/openai-wire.ts +3 -2
  92. package/src/{serve → server}/pipeline.ts +1 -1
  93. package/src/server/prompt-builder.ts +13 -0
  94. package/src/server/prompt-contracts.ts +17 -0
  95. package/src/server/proxy-routes.ts +187 -0
  96. package/src/server/publishing-routes.ts +41 -0
  97. package/src/{serve → server}/request-plan.ts +6 -8
  98. package/src/{serve → server}/request-prep.ts +47 -50
  99. package/src/{serve → server}/responses-client.ts +30 -13
  100. package/src/{responses.ts → server/responses.ts} +12 -93
  101. package/src/server/routes.ts +205 -0
  102. package/src/server/start.ts +72 -0
  103. package/src/server/status-routes.ts +108 -0
  104. package/src/{serve → server}/text-completion-stage.ts +25 -4
  105. package/src/server/text-prompt.ts +12 -0
  106. package/src/{serve → server}/token-streams.ts +36 -38
  107. package/src/server/worker-routes.ts +311 -0
  108. package/src/storage/paths.ts +61 -0
  109. package/src/web/assets.ts +37 -0
  110. package/src/web/{src → browser}/api.ts +5 -23
  111. package/src/web/browser/chat-host.ts +17 -0
  112. package/src/web/browser/installed-panels.ts +6 -0
  113. package/src/web/browser/main.ts +55 -0
  114. package/src/web/browser/markdown.ts +279 -0
  115. package/src/web/browser/memory-panel.ts +9 -0
  116. package/src/web/browser/palette.ts +64 -0
  117. package/src/web/browser/protocol.ts +13 -0
  118. package/src/web/browser/shell.ts +467 -0
  119. package/src/web/{src → browser}/status.ts +32 -36
  120. package/src/web/build.ts +51 -0
  121. package/src/web/public/app.html +1054 -0
  122. package/src/web/{sw.js → public/sw.js} +4 -3
  123. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  124. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  125. package/THIRD_PARTY_LICENSES.md +0 -51
  126. package/docs/README.md +0 -107
  127. package/docs/archive/hlg-sampling.md +0 -350
  128. package/docs/archive/investigations/audio-input-plan.md +0 -356
  129. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
  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/release-notes-v0.4.0.md +0 -45
  174. package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
  175. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  176. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  177. package/docs/design/batching.md +0 -2054
  178. package/docs/design/decode-speed-program.md +0 -2404
  179. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  180. package/docs/design/generic-model-support.md +0 -821
  181. package/docs/design/kv-cache.md +0 -993
  182. package/docs/design/orpo-training.md +0 -680
  183. package/docs/design/speculative-decoding.md +0 -2129
  184. package/docs/design/turboquant.md +0 -2225
  185. package/docs/design/unified-engine-frontier-plan.md +0 -1987
  186. package/docs/design/web-chat-redesign.md +0 -695
  187. package/docs/planning/PRODUCT_ROADMAP.md +0 -593
  188. package/docs/planning/ResearchTopics.md +0 -119
  189. package/docs/planning/public-readiness-handoff.md +0 -244
  190. package/docs/planning/public-readiness.md +0 -149
  191. package/docs/planning/video-series.md +0 -421
  192. package/docs/reference/benchmarks.md +0 -3587
  193. package/docs/reference/cli.md +0 -646
  194. package/docs/reference/distribution.md +0 -380
  195. package/docs/reference/environment.md +0 -494
  196. package/docs/reference/glossary.md +0 -39
  197. package/docs/reference/library-api.md +0 -688
  198. package/docs/reference/memory.md +0 -260
  199. package/docs/reference/models.md +0 -346
  200. package/docs/reference/server-api.md +0 -1945
  201. package/docs/reference/server-config.md +0 -973
  202. package/docs/reference/training.md +0 -462
  203. package/docs/reference/troubleshooting.md +0 -158
  204. package/src/admission-plan.ts +0 -18
  205. package/src/audio/audiotoolbox.ts +0 -112
  206. package/src/audio/conformer.ts +0 -655
  207. package/src/audio/decode.ts +0 -133
  208. package/src/audio/features.ts +0 -202
  209. package/src/audio/mic-capture.ts +0 -98
  210. package/src/audio/silero-vad.ts +0 -379
  211. package/src/audio/transcode.ts +0 -67
  212. package/src/audio/whisper-decode.ts +0 -774
  213. package/src/audio/whisper-fast.ts +0 -732
  214. package/src/audio/whisper-format.ts +0 -73
  215. package/src/audio/whisper-mel.ts +0 -185
  216. package/src/audio/whisper-timing.ts +0 -274
  217. package/src/audio/whisper-tokenizer.ts +0 -239
  218. package/src/audio/whisper-transcribe.ts +0 -410
  219. package/src/backends/mlx/assistant-target.ts +0 -46
  220. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  221. package/src/backends/mlx/autoregressive.ts +0 -129
  222. package/src/backends/mlx/batch-group.ts +0 -1874
  223. package/src/backends/mlx/cache-attachment.ts +0 -67
  224. package/src/backends/mlx/cache-layout.ts +0 -31
  225. package/src/backends/mlx/checkpoint-state.ts +0 -53
  226. package/src/backends/mlx/continuation-persistence.ts +0 -107
  227. package/src/backends/mlx/continuation-request.ts +0 -43
  228. package/src/backends/mlx/continuation.ts +0 -77
  229. package/src/backends/mlx/diffusion.ts +0 -39
  230. package/src/backends/mlx/draft-target.ts +0 -32
  231. package/src/backends/mlx/encoder-cache.ts +0 -25
  232. package/src/backends/mlx/evaluation.ts +0 -105
  233. package/src/backends/mlx/fill-append.ts +0 -58
  234. package/src/backends/mlx/fill-group.ts +0 -497
  235. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  236. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  237. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  238. package/src/backends/mlx/gateway-binding.ts +0 -174
  239. package/src/backends/mlx/graph.ts +0 -38
  240. package/src/backends/mlx/kv-codec.ts +0 -9
  241. package/src/backends/mlx/kv-maintenance.ts +0 -161
  242. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  243. package/src/backends/mlx/memory-client.ts +0 -189
  244. package/src/backends/mlx/methods.ts +0 -90
  245. package/src/backends/mlx/mixed-iteration.ts +0 -62
  246. package/src/backends/mlx/model-prompt.ts +0 -178
  247. package/src/backends/mlx/model-serving.ts +0 -80
  248. package/src/backends/mlx/paged-cache-codec.ts +0 -27
  249. package/src/backends/mlx/prefill-cohort.ts +0 -100
  250. package/src/backends/mlx/prefill-policy.ts +0 -26
  251. package/src/backends/mlx/prefill-rows.ts +0 -244
  252. package/src/backends/mlx/prefill.ts +0 -33
  253. package/src/backends/mlx/projected-context-rows.ts +0 -72
  254. package/src/backends/mlx/prompt-input.ts +0 -29
  255. package/src/backends/mlx/qwen-prompt-input.ts +0 -40
  256. package/src/backends/mlx/request-policy.ts +0 -20
  257. package/src/backends/mlx/request-state-policy.ts +0 -54
  258. package/src/backends/mlx/rollback.ts +0 -92
  259. package/src/backends/mlx/row-sampling.ts +0 -49
  260. package/src/backends/mlx/serial-executor.ts +0 -251
  261. package/src/backends/mlx/speculative-group.ts +0 -438
  262. package/src/backends/mlx/speculative-round.ts +0 -161
  263. package/src/backends/mlx/speculative.ts +0 -131
  264. package/src/backends/mlx/state-rows.ts +0 -104
  265. package/src/backends/mlx/state-views.ts +0 -46
  266. package/src/backends/mlx/target-layout-capability.ts +0 -35
  267. package/src/backends/mlx/text-engine.ts +0 -73
  268. package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
  269. package/src/chat-template.ts +0 -382
  270. package/src/cli.ts +0 -3490
  271. package/src/config.ts +0 -399
  272. package/src/contracts/completion.ts +0 -16
  273. package/src/contracts/execution.ts +0 -70
  274. package/src/contracts/generation.ts +0 -103
  275. package/src/contracts/host.ts +0 -7
  276. package/src/contracts/object-cache.ts +0 -8
  277. package/src/contracts/pi-provider.ts +0 -30
  278. package/src/contracts/pi.ts +0 -261
  279. package/src/contracts/prefix-cache.ts +0 -33
  280. package/src/contracts/resources.ts +0 -25
  281. package/src/contracts/sampling.ts +0 -23
  282. package/src/contracts/scheduling.ts +0 -54
  283. package/src/contracts/tsconfig.json +0 -14
  284. package/src/dataset/generators.ts +0 -1087
  285. package/src/dataset/index.ts +0 -12
  286. package/src/dataset/job.ts +0 -81
  287. package/src/dataset/llm.ts +0 -71
  288. package/src/dataset/registry.ts +0 -528
  289. package/src/diffusion/diffusion-generate.ts +0 -507
  290. package/src/download.ts +0 -505
  291. package/src/embed.ts +0 -77
  292. package/src/engine/admission.ts +0 -59
  293. package/src/engine/cancellation.ts +0 -38
  294. package/src/engine/engine.ts +0 -56
  295. package/src/engine/execution-coordinator.ts +0 -70
  296. package/src/engine/execution-plan.ts +0 -64
  297. package/src/engine/execution-tasks.ts +0 -44
  298. package/src/engine/namespaced-cache.ts +0 -13
  299. package/src/engine/resources.ts +0 -53
  300. package/src/engine/scheduler.ts +0 -92
  301. package/src/engine/session.ts +0 -247
  302. package/src/eval/README.md +0 -130
  303. package/src/eval/ifeval.ts +0 -81
  304. package/src/eval/kl-prompts.ts +0 -29
  305. package/src/eval/kl.ts +0 -590
  306. package/src/eval/perplexity.ts +0 -164
  307. package/src/eval/quality-db.ts +0 -92
  308. package/src/eval/reference-logits.ts +0 -207
  309. package/src/eval/runner.ts +0 -124
  310. package/src/eval/score.ts +0 -49
  311. package/src/eval/tasks/bfcl.ts +0 -535
  312. package/src/eval/tasks/gsm8k.ts +0 -98
  313. package/src/eval/tasks/hashhop.ts +0 -139
  314. package/src/eval/tasks/humaneval.ts +0 -275
  315. package/src/eval/tasks/ifeval.ts +0 -525
  316. package/src/eval/tasks/mmlu.ts +0 -157
  317. package/src/eval/ultrafeedback.ts +0 -60
  318. package/src/evaldb.ts +0 -199
  319. package/src/expert-io.ts +0 -393
  320. package/src/expert-offload-build.ts +0 -77
  321. package/src/expert-offload.ts +0 -76
  322. package/src/expert-residency.ts +0 -1134
  323. package/src/expert-usage.ts +0 -415
  324. package/src/fill/echo-index.ts +0 -188
  325. package/src/fill/fill-session.ts +0 -463
  326. package/src/fill/proposal.ts +0 -68
  327. package/src/fill/schema-rows.ts +0 -506
  328. package/src/fill/tool-boundary.ts +0 -103
  329. package/src/fit.ts +0 -249
  330. package/src/generate.ts +0 -1352
  331. package/src/grammar.ts +0 -604
  332. package/src/harness-pi.ts +0 -184
  333. package/src/hf-push.ts +0 -628
  334. package/src/hub-rest.ts +0 -242
  335. package/src/index.ts +0 -63
  336. package/src/inference/denoising.ts +0 -17
  337. package/src/inference/draft-acceptance.ts +0 -41
  338. package/src/inference/draft-output.ts +0 -49
  339. package/src/inference/graph.ts +0 -33
  340. package/src/inference/prefill.ts +0 -45
  341. package/src/inference/rollback.ts +0 -7
  342. package/src/jobs/index.ts +0 -31
  343. package/src/jobs/job-entry.ts +0 -107
  344. package/src/jobs/task-client.ts +0 -19
  345. package/src/jobs/types.ts +0 -2
  346. package/src/kv-scheme.ts +0 -279
  347. package/src/kv-store.ts +0 -1135
  348. package/src/lab/README.md +0 -22
  349. package/src/lab/curve/curve-designer.html +0 -303
  350. package/src/lab/curve/curve-sampler.ts +0 -122
  351. package/src/lab/expert-trace/expert-trace.ts +0 -69
  352. package/src/lab/paged-kv/paged-attention.ts +0 -117
  353. package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
  354. package/src/lab/paged-kv/paged-kv.ts +0 -336
  355. package/src/library.ts +0 -40
  356. package/src/lora.ts +0 -408
  357. package/src/md-modules.d.ts +0 -54
  358. package/src/media-fetch.ts +0 -442
  359. package/src/memory/article.ts +0 -558
  360. package/src/memory/chunk-validation.ts +0 -150
  361. package/src/memory/chunk.ts +0 -318
  362. package/src/memory/cluster.ts +0 -351
  363. package/src/memory/coverage.ts +0 -134
  364. package/src/memory/crosslink.ts +0 -0
  365. package/src/memory/db.ts +0 -253
  366. package/src/memory/entity.ts +0 -203
  367. package/src/memory/gate.ts +0 -187
  368. package/src/memory/history.ts +0 -152
  369. package/src/memory/ingest.ts +0 -335
  370. package/src/memory/model.ts +0 -183
  371. package/src/memory/normalize.ts +0 -671
  372. package/src/memory/parse.ts +0 -22
  373. package/src/memory/pipeline.ts +0 -275
  374. package/src/memory/prompts.ts +0 -65
  375. package/src/memory/query.ts +0 -334
  376. package/src/memory/reconcile.ts +0 -734
  377. package/src/memory/redirect.ts +0 -108
  378. package/src/memory/reindex.ts +0 -325
  379. package/src/memory/resolve.ts +0 -307
  380. package/src/memory/rest.ts +0 -245
  381. package/src/memory/route.ts +0 -272
  382. package/src/memory/schedule.ts +0 -165
  383. package/src/memory/stages.ts +0 -777
  384. package/src/memory/synthesize.ts +0 -1638
  385. package/src/memory/tools.ts +0 -749
  386. package/src/memory/vault.ts +0 -1194
  387. package/src/memory/wikify.ts +0 -1064
  388. package/src/mlx/array.ts +0 -425
  389. package/src/mlx/autograd.ts +0 -304
  390. package/src/mlx/checkpoint.ts +0 -149
  391. package/src/mlx/compile.ts +0 -168
  392. package/src/mlx/custom-vjp.ts +0 -188
  393. package/src/mlx/ffi.ts +0 -531
  394. package/src/mlx/materialize.ts +0 -23
  395. package/src/mlx/metal-kernel.ts +0 -159
  396. package/src/mlx/normalized-argmax.ts +0 -116
  397. package/src/mlx/ops.ts +0 -1108
  398. package/src/mlx/quantized-rows.ts +0 -36
  399. package/src/mlx/token-bitmask.ts +0 -52
  400. package/src/mlx/turboquant-kv-decode.ts +0 -82
  401. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  402. package/src/mlx/turboquant-ops.ts +0 -861
  403. package/src/mlx/turboquant-tables.ts +0 -237
  404. package/src/mmap.ts +0 -90
  405. package/src/model/artifact-identity.ts +0 -73
  406. package/src/model/batched-kv.ts +0 -235
  407. package/src/model/batched-mask.ts +0 -279
  408. package/src/model/batched-quant.ts +0 -212
  409. package/src/model/batched-quantized-kv.ts +0 -144
  410. package/src/model/batched-rotating-quant.ts +0 -353
  411. package/src/model/batched-rotating-state.ts +0 -149
  412. package/src/model/batched-rotating.ts +0 -338
  413. package/src/model/batched-row-storage.ts +0 -179
  414. package/src/model/batched-ssm.ts +0 -52
  415. package/src/model/batched-turboquant-kv.ts +0 -94
  416. package/src/model/compiled-decode.ts +0 -712
  417. package/src/model/decoded-kv-donor.ts +0 -12
  418. package/src/model/delayed-quantized-kv.ts +0 -72
  419. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  420. package/src/model/delayed-turboquant-kv.ts +0 -57
  421. package/src/model/diffusion-gemma.ts +0 -1026
  422. package/src/model/factory.ts +0 -215
  423. package/src/model/fingerprint.ts +0 -45
  424. package/src/model/flash-attention.ts +0 -694
  425. package/src/model/full-prefill-padding.ts +0 -56
  426. package/src/model/full-prefill-row.ts +0 -105
  427. package/src/model/gemma4-base.ts +0 -2370
  428. package/src/model/gemma4.ts +0 -1395
  429. package/src/model/generated/gemma4-12b.ts +0 -429
  430. package/src/model/generated/gemma4-26b.ts +0 -448
  431. package/src/model/generated/gemma4-e4b.ts +0 -717
  432. package/src/model/generated/index.ts +0 -18
  433. package/src/model/glm52-atlas.ts +0 -511
  434. package/src/model/glm52-cache.ts +0 -792
  435. package/src/model/glm52-config.ts +0 -262
  436. package/src/model/glm52-container.ts +0 -305
  437. package/src/model/glm52-coupling.ts +0 -388
  438. package/src/model/glm52-dsa.ts +0 -606
  439. package/src/model/glm52-expert-layout.ts +0 -253
  440. package/src/model/glm52-layout.ts +0 -152
  441. package/src/model/glm52-memory.ts +0 -500
  442. package/src/model/glm52-mla.ts +0 -792
  443. package/src/model/glm52-moe.ts +0 -223
  444. package/src/model/glm52-pilot.ts +0 -537
  445. package/src/model/glm52-reference.ts +0 -445
  446. package/src/model/glm52-residency.ts +0 -557
  447. package/src/model/glm52-resident-weights.ts +0 -135
  448. package/src/model/glm52-streamed-experts.ts +0 -453
  449. package/src/model/glm52-streamed-metal.ts +0 -610
  450. package/src/model/glm52-weights.ts +0 -503
  451. package/src/model/glm52.ts +0 -1132
  452. package/src/model/implementation.ts +0 -69
  453. package/src/model/kv-attention-view.ts +0 -70
  454. package/src/model/minicpm5.ts +0 -376
  455. package/src/model/profile.ts +0 -468
  456. package/src/model/quantized-append-attention.ts +0 -31
  457. package/src/model/qwen-append.ts +0 -12
  458. package/src/model/qwen-conv.ts +0 -52
  459. package/src/model/qwen3-delta-state.ts +0 -74
  460. package/src/model/qwen3-delta.ts +0 -451
  461. package/src/model/qwen3-moe.ts +0 -404
  462. package/src/model/qwen3-mrope.ts +0 -250
  463. package/src/model/qwen3.ts +0 -277
  464. package/src/model/qwen3_5-checkpoint.ts +0 -164
  465. package/src/model/qwen3_5.ts +0 -881
  466. package/src/model/rotating-kv-donor.ts +0 -35
  467. package/src/model/rotating-kv-layout.ts +0 -262
  468. package/src/model/rotating-row-transaction.ts +0 -35
  469. package/src/model/speculative-rotating-kv.ts +0 -101
  470. package/src/model/ssm-prefill-padding.ts +0 -39
  471. package/src/model/support.ts +0 -110
  472. package/src/model/token-groups.ts +0 -66
  473. package/src/model/trellis-balanced-scatter.ts +0 -51
  474. package/src/model/trellis-linear.ts +0 -672
  475. package/src/model/trellis-shared-m.ts +0 -151
  476. package/src/model/trellis-shared-scatter.ts +0 -144
  477. package/src/model/trellis-splitk-prefill.ts +0 -158
  478. package/src/model/trellis-tiled-prefill.ts +0 -136
  479. package/src/model/trellis-vector-expand.ts +0 -62
  480. package/src/model/trellis-wide-prefill.ts +0 -94
  481. package/src/model/turboquant-codec.ts +0 -89
  482. package/src/model/universal/archs.ts +0 -332
  483. package/src/model/universal/dense.ts +0 -612
  484. package/src/model/universal/modules.ts +0 -170
  485. package/src/model/universal/rope.ts +0 -381
  486. package/src/model/whisper.ts +0 -435
  487. package/src/native/expert_io.c +0 -523
  488. package/src/native/frame_extract.swift +0 -140
  489. package/src/native/mic_capture.swift +0 -92
  490. package/src/native-pack.ts +0 -163
  491. package/src/pi-provider.ts +0 -53
  492. package/src/pi-session.ts +0 -81
  493. package/src/pi-terminal.ts +0 -274
  494. package/src/pi-web.ts +0 -1940
  495. package/src/preflight.ts +0 -158
  496. package/src/prompt-cache.ts +0 -682
  497. package/src/quantize/allocator.ts +0 -627
  498. package/src/quantize/atomic-output.ts +0 -38
  499. package/src/quantize/calibration.ts +0 -181
  500. package/src/quantize/config-writer.ts +0 -145
  501. package/src/quantize/index.ts +0 -84
  502. package/src/quantize/job.ts +0 -162
  503. package/src/quantize/quantizer.ts +0 -666
  504. package/src/quantize/rotate.ts +0 -603
  505. package/src/quantize/safetensors-writer.ts +0 -249
  506. package/src/quantize/sensitivity.ts +0 -216
  507. package/src/quantize/trellis.ts +0 -586
  508. package/src/quantize/weight-transform.ts +0 -292
  509. package/src/registry.ts +0 -602
  510. package/src/runtime-config.ts +0 -77
  511. package/src/safetensors.ts +0 -165
  512. package/src/sampler.ts +0 -1012
  513. package/src/serve/admin-routes.ts +0 -184
  514. package/src/serve/assets/curve-terrain.html +0 -105
  515. package/src/serve/assets/training-inference-map.html +0 -575
  516. package/src/serve/audio-routes.ts +0 -323
  517. package/src/serve/aux-routes.ts +0 -132
  518. package/src/serve/batch-scheduler.ts +0 -8
  519. package/src/serve/checkpoint-identity.ts +0 -64
  520. package/src/serve/generation-gateway.ts +0 -537
  521. package/src/serve/isolate.ts +0 -609
  522. package/src/serve/kv-budget.ts +0 -14
  523. package/src/serve/lab-routes.ts +0 -341
  524. package/src/serve/lane-registry.ts +0 -45
  525. package/src/serve/model-admin-routes.ts +0 -155
  526. package/src/serve/model-binding.ts +0 -49
  527. package/src/serve/model-host.ts +0 -511
  528. package/src/serve/parent-application.ts +0 -56
  529. package/src/serve/prompt-response-trace.ts +0 -161
  530. package/src/serve/response-lease.ts +0 -24
  531. package/src/serve/session-search.ts +0 -326
  532. package/src/serve/static-routes.ts +0 -101
  533. package/src/serve/transcription-server.ts +0 -64
  534. package/src/serve/transcription-service.ts +0 -502
  535. package/src/server.ts +0 -1282
  536. package/src/spec/assistant-rows.ts +0 -93
  537. package/src/spec/assistant-source.ts +0 -126
  538. package/src/spec/cache-identity.ts +0 -22
  539. package/src/spec/deepspec-rows.ts +0 -29
  540. package/src/spec/deepspec-source.ts +0 -145
  541. package/src/spec/dflash-source.ts +0 -149
  542. package/src/spec/drafter.ts +0 -304
  543. package/src/spec/dspark/ab-stats.ts +0 -136
  544. package/src/spec/dspark/calibration.ts +0 -112
  545. package/src/spec/dspark/data-dflash.ts +0 -156
  546. package/src/spec/dspark/data.ts +0 -201
  547. package/src/spec/dspark/deepspec-module.ts +0 -776
  548. package/src/spec/dspark/generate-dflash.ts +0 -245
  549. package/src/spec/dspark/generate.ts +0 -290
  550. package/src/spec/dspark/loader.ts +0 -23
  551. package/src/spec/dspark/loss.ts +0 -213
  552. package/src/spec/dspark/module-dflash.ts +0 -560
  553. package/src/spec/dspark/module.ts +0 -540
  554. package/src/spec/dspark/quantize-drafter.ts +0 -91
  555. package/src/spec/dspark/sample.ts +0 -112
  556. package/src/spec/generate.ts +0 -276
  557. package/src/spec/glm52-mtp-graph.ts +0 -29
  558. package/src/spec/glm52-mtp-rows.ts +0 -132
  559. package/src/spec/glm52-mtp-source.ts +0 -318
  560. package/src/spec/glm52-mtp-state.ts +0 -33
  561. package/src/spec/ngram-source.ts +0 -226
  562. package/src/spec/projected-draft-rows.ts +0 -73
  563. package/src/spec/qwen-mtp-module.ts +0 -171
  564. package/src/spec/qwen-mtp-rows.ts +0 -230
  565. package/src/spec/qwen-mtp-source.ts +0 -386
  566. package/src/spec/qwen-mtp-state.ts +0 -30
  567. package/src/spec/serve-loop.ts +0 -587
  568. package/src/spec/source.ts +0 -228
  569. package/src/spec/two-model-rows.ts +0 -62
  570. package/src/spec/two-model.ts +0 -113
  571. package/src/ssd-cache.ts +0 -431
  572. package/src/ssd-durability.ts +0 -209
  573. package/src/storage/host-buffer.ts +0 -24
  574. package/src/storage/kv-writer.ts +0 -83
  575. package/src/storage/kv-writer.worker.js +0 -264
  576. package/src/storage/retention-policy.ts +0 -37
  577. package/src/tiered-prompt-cache.ts +0 -45
  578. package/src/tokenizer.ts +0 -335
  579. package/src/tool-approvals.ts +0 -131
  580. package/src/tool-call.ts +0 -695
  581. package/src/train/dataset.ts +0 -484
  582. package/src/train/diffusion-lora.ts +0 -216
  583. package/src/train/export.ts +0 -32
  584. package/src/train/flash-cce.ts +0 -1234
  585. package/src/train/forward.ts +0 -266
  586. package/src/train/fuse.ts +0 -243
  587. package/src/train/index.ts +0 -46
  588. package/src/train/job.ts +0 -205
  589. package/src/train/lora-params.ts +0 -254
  590. package/src/train/loss.ts +0 -1591
  591. package/src/train/merge.ts +0 -195
  592. package/src/train/optimizer.ts +0 -183
  593. package/src/train/prefix-shared.ts +0 -490
  594. package/src/train/rank.ts +0 -137
  595. package/src/train/segmented.ts +0 -1828
  596. package/src/train/steel-qmm-header.ts +0 -1461
  597. package/src/train/trainer.ts +0 -1221
  598. package/src/train/watch.ts +0 -542
  599. package/src/vision/diffusion-vision.ts +0 -620
  600. package/src/vision/embedder.ts +0 -176
  601. package/src/vision/preprocess.ts +0 -247
  602. package/src/vision/prompt.ts +0 -409
  603. package/src/vision/qwen3vl-preprocess.ts +0 -409
  604. package/src/vision/qwen3vl-prompt.ts +0 -233
  605. package/src/vision/qwen3vl-tower.ts +0 -566
  606. package/src/vision/siglip.ts +0 -607
  607. package/src/vision/video-frames.ts +0 -148
  608. package/src/web/app.html +0 -2155
  609. package/src/web/app.js +0 -5863
  610. package/src/web/skills/memory/SKILL.md +0 -120
  611. package/src/web/skills/web-research/SKILL.md +0 -46
  612. package/src/web/skills.ts +0 -97
  613. package/src/web/src/adapters-panel.ts +0 -288
  614. package/src/web/src/assistant.ts +0 -451
  615. package/src/web/src/chat.ts +0 -1060
  616. package/src/web/src/composer.ts +0 -962
  617. package/src/web/src/dataset.ts +0 -132
  618. package/src/web/src/finetune.ts +0 -267
  619. package/src/web/src/hub.ts +0 -428
  620. package/src/web/src/main.ts +0 -98
  621. package/src/web/src/markdown.ts +0 -0
  622. package/src/web/src/memory-panel.ts +0 -572
  623. package/src/web/src/model-picker.ts +0 -159
  624. package/src/web/src/palette.ts +0 -346
  625. package/src/web/src/protocol.ts +0 -26
  626. package/src/web/src/quantize.ts +0 -167
  627. package/src/web/src/rag.ts +0 -274
  628. package/src/web/src/sessions.ts +0 -469
  629. package/src/web/src/shell.ts +0 -804
  630. package/src/web/src/ui-catalog.ts +0 -78
  631. package/src/web/src/voice.ts +0 -141
  632. package/src/web/vendor/README.md +0 -61
  633. package/src/web-assets.ts +0 -47
  634. package/src/web-tools.ts +0 -478
  635. package/src/weights.ts +0 -255
  636. /package/src/{serve → server}/completion-sink.ts +0 -0
  637. /package/src/{serve → server}/generated-token-history.ts +0 -0
  638. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  639. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  640. /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>