feat: wire browser deployment with binary tokenizer format
WASM init was hanging because std.json.parseFromSlice on the 20MB
tokenizer.json (248K vocab + 248K merges) creates millions of heap
allocations via memory.grow. Replace with a compact binary format
(.tkn) that loads via flat array reads in O(n).
- Add scripts/convert_tokenizer.py (JSON -> .tkn binary converter)
- Add Tokenizer.loadFromBinary() with TOKN magic auto-detection
- Update dist.sh to validate model files, convert tokenizer, copy
model.q4 + tokenizer.tkn into dist/
- Update app to download tokenizer.tkn + model.q4, store both in
IndexedDB, pass to init_with_tokenizer() via WASM
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: a3bc79e811d3