server.js: /llm-status probe + /llm-chat proxy to the local llama.cpp
OpenAI-compatible server (192.168.3.7:1234, model ctx 131072, 2 parallel
sessions). Model name, base URL and token budget pinned server-side
(LLM_BASE/LLM_MODEL/LLM_MAX_TOKENS env to override); non-streaming, since
the hidden thinking text shares max_tokens with the visible answer.
app.js: checkLLM() alongside checkRouter(); free-form chat now goes to the
model with a compact live plan snapshot (bookings, stays, per-day stops
with times) as system context. Deterministic UI intents (discovery
drawer, time nudges, swaps) stay local — the LLM proposes, the UI
commits. Canned-reply fallback when the server is down or the model is
not loaded; status badge now reads e.g. 'online · router · llm'.
The mock can now work several trips at once: a trip picker in the
topbar, per-trip state in localStorage (edits + version history survive
switching), and a per-trip router key so each trip routes on its own
OSRM extract.
Colombia (Cartagena -> Santa Marta, 8 days) becomes the default working
trip, inside a new walking-profile OSRM instance:
- scripts/crop_pbf.py: streaming 3-pass PBF cropper (no PBF library;
the country file is too big for osmium extract -s complete_ways on
this box). Framing validated against osmium test fixtures and
osrm-extract. Drops relations (foot profile ignores restrictions).
- scripts/setup-osrm-colombia.sh: download -> crop (~4.6 MB) ->
extract/partition/customize with the official foot.lua -> serve
:5003. Verified: Getsemaní -> Castillo San Felipe 7.98 km / 96 min.
- server.js: ROUTERS map, ?router=colombia|northeast on /route,
/table, /router-status (per-router probe points).
- app.js: legs touching a transit stop are fixed (flight/taxi/bus via
M.multimodal), never re-routed; distance-0 router answers (both
points on one node) read as adjacent stops, not out-of-coverage.
- multi-hotel fix: day-scope map fit uses the stays covering THAT day,
so a two-city trip no longer fits the whole country per day.
Also: pre-cache-tiles.sh (Cartagena+Santa Marta z14-16, 2560 tiles),
tile cache write fix (Node rejects flags:'x'; buffer-then-write),
favicon, renderHotelMks load-order guard, tests updated for the new
default trip (all four puppeteer suites green, zero console errors).
- server.js: proxy /route, /table, /router-status to the local OSRM on :5000
- app.js: routeClient (polyline-5 decode, ordered route fetch); legs start as
straight-line estimates (conf 1) and are upgraded in the background to real
road geometry + duration (conf 3); out-of-coverage trips (Florence) fall
back gracefully with a 'estimate — outside router coverage' source
- L3 leg editor: dragging a waypoint now genuinely re-routes through the
router (was silently no-op — #app covered the map with pointer-events:auto,
so no map drag ever landed; #app is now pointer-events:none, children opt in)
- data.js: second demo city (Boston 14–16 Sep, inside the router's NE-US
extract) via ?city=boston; nudges + multimodal legs are now dataset-driven
- L0: Day/Trip scope toggle — per-day summary cards (pacing bar, stops,
end time, price, base) with click-to-jump; map fits the whole trip
- version history: commit() snapshots days+stays on every mutation; topbar
vN pill with undo/redo + dropdown timeline showing a diff label per version;
Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y; restore() re-enriches legs (snapshots may
predate route enrichment)
- offline: staged 'prepare for offline' card in the trip rail (itinerary →
POI details → vector tiles) that flips the topbar badge to '📦 offline ready'
- chat/scripts/nudges: Florence-specific strings generalized (stay name/dates,
vibes, pacing summary) so both demo cities read naturally