EYAS v0.8.14-beta — Shape your own landing page
The landing page stops being something you're handed and becomes something you shape. The fixed
dashboard is gone; a nine-tile grid takes its place, and the extension point it's built on had
been sitting declared and unused since before this feature existed.
Home
- Widget grid at
/: drag to move, drag a corner to resize, remove a tile, or open a drawer
and add one — including tiles from disabled modules, shown dimmed so you can see what could be
there. Layout is per user and per breakpoint (lg/md/smarrange independently) and saves
itself ~800ms after you stop dragging. - Factory nine: Pulse, Attention, Running agents, Schedule, Conversations, Board, Briefing,
Cost, System. No stored layout means the factory layout applies — so a later release that adds
a tile reaches everyone who never customised, automatically. A customised user is instead
offered any newly-added factory widgets ("Add" / "No thanks"), never handed them silently. - Tiles fail alone. A per-tile error boundary means a broken module shows "Unavailable" on
its own tile; the other eight keep working. - Disabled-module tiles survive. A tile from a disabled module drops out of the rendered grid
but keeps its stored position and config, and returns intact when the module is re-enabled. - The widget extension point is alive.
FrontendManifest.widgets/WidgetRegistration
(src/core/types.ts) were declared and typed but nothing populated or read them. The new
homemodule now collects them from the module loader and serves them at
GET /api/v1/home/widgets; a contract test forbids a manifest-declared widget with no frontend
component, or the reverse. - Setup requests collapse:
SetupRecommendationsCardfired 10 requests on every open
(providers, projects, prompts, agents, search sources, backups, ingress, autonomy, vault,
communication). It now calls one server-cached aggregate,GET /api/v1/home/setup-status. - Dead code removed:
AutonomyNudgeCard— never imported, never rendered — is deleted, along
with the fixed dashboard page it used to live on. - Handbook:
daily/homedocuments the grid, edit mode, add/remove/resize, restoring the factory
layout, and the new-widget offer, in en, hu, de, es, fr and tlh.
Security
- The home endpoints were never authenticated.
homecreated its routes inonRegister, which
runs for every module before any module'sonStart— where auth mounts its middleware. Hono
composes middleware in registration order, so nothing auth registered could ever apply: every
/api/v1/home/*request failed with 401 and the UI bounced the user straight back to the login
screen. Routes now mount inonStartandhomedeclaresauthas a dependency, which forces the
order through the loader's topological sort. CSRF pairing added for the mutating layout routes. - A contract test now asserts what a route test structurally cannot. Every route test in this
repo installs its ownc.set('userId', …), i.e. simulates a world where auth already ran — which
is why thousands of green tests never saw the above.api-auth-coverage.contract.test.tsruns the
real dependency resolver over the real registration order and fails if a module that mounts routes
lands beforeauth, or if an/api/v1segment is neither covered nor on a named public list.
Fixed
- Each breakpoint keeps its own arrangement. The grid loaded the layout once at
lgand never
reloaded, so crossing a width threshold made the library derive anmdlayout from thelgone
and save it — creating a stored row for someone who never customised (which stops future factory
widgets reaching them) and flattening a deliberately arranged desktop layout on the way back. - Tiles stay inside their tiles. Content larger than its cell escaped the frame and painted over
neighbouring panels; it is now contained, with a visible scroll affordance where it scrolls. Pulse
stays readable at its minimum height instead of clipping its own figures. - A failed fetch no longer reads as good news. Attention, Conversations, Briefing and Board
rendered a backend failure as a successful empty state — a dead approvals endpoint said "Nothing
needs your attention". All nine tiles now report an unavailable source as unavailable.
Known issues
- The Privacy page bounces to login, for the same reason the home page did:
privacyregisters
beforeauth, so/api/v1/privacy/*never passes through the auth middleware. Its handlers use
requirePermission, so the endpoints fail closed rather than being exposed — but the page is
unusable. Not fixed here:privacy's registration position is load-bearing for model wrapping. - 17 route segments with mutating endpoints have no CSRF pairing (a2a, artifacts, client-wiki,
connections, costops, data-port, federation, ideas, intel, internal, ops, privacy, prompt-coach,
skill-generation, system, team-sessions, voice). Pre-existing; frozen in a self-checking baseline
so the list cannot grow unnoticed. - Disabling
authwould start every module unprotected.startAllnever checks that a live
module's declared dependencies are enabled, andEyasModule.requiredis declared but read nowhere. - Visual layout was verified by a human on one screen size only; jsdom performs no layout, so no
automated test covers rendering, drag-and-drop or resize.