Opening an in-progress session that has a live Pi runtime now reconnects to
its pending gate instead of the empty landing screen that read as "stopped".
Cold/completed sessions keep the read-only documents panel with its explicit
Resume, so a mere click never spawns a runtime. Backend GET /sessions now
reports a per-session `active` flag (live runtime bound) to drive this.
Also:
- "New session" now closes any open session detail panel (left box).
- The model-activity separator can be dragged to a full 50/50 split
(was capped at 576px); central-min still guards narrow viewports.
Test fixes uncovered along the way:
- Node 25 ships an experimental global localStorage that shadows jsdom's and
lacks clear(), failing every jsdom test at setup; install a spec-compliant
in-memory Storage (feature-detected, inert on CI/LTS).
- Fix 4 pre-existing session-mgmt tests that used an ambiguous getByText for a
session shown in both nav and header; target the nav item by test id.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The embedded mode sets VITE_BACKEND_URL=/datamart-builder/api (the nginx
proxy path), but the runtime-config policy only allowed /api. This caused
resolveBackendUrl() to throw at app startup, resulting in a blank SPA.
Add /datamart-builder/api and /datamart-builder/api/ to relativeBases and
test cases.
Body-less POSTs (resume, close) sent content-type: application/json with no
body, so Fastify rejected them with FST_ERR_CTP_EMPTY_JSON_BODY (400) and
clicking an existing session never reopened it. apiFetch now adds the header
only when init.body is set.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>