chore: untrack dashboard build output (stale by 13 commits on the pip path) (#151)

* chore(dashboard): untrack committed frontend build output

work/meshai/dashboard/static/ held committed vite build artifacts
(index.html + hashed assets/*.js|css + copied public/ images) that were
last built 2026-07-07 (PR #87), 13 frontend commits ago. Docker builds
the frontend fresh and overwrites these on every image build, but the
pip install -e . path (documented in README Quick start) ships this
stale directory verbatim via [tool.setuptools.packages.find] include.

The root .gitignore already had a rule for this
("meshai/dashboard/static/") but it silently stopped matching when
2e1fb325 moved the source tree into work/ -- gitignore patterns
containing a "/" are anchored to the .gitignore's own directory, so the
unprefixed pattern only ever matched a repo-root meshai/dashboard/static/
that hasn't existed since that move. Fixed by prefixing with work/,
matching the existing work/data/secrets/.env convention elsewhere in
the file.

Every file under static/ is generated: assets/* and index.html come
from `vite build` (outDir: ../meshai/dashboard/static, emptyOutDir:
true, confirmed in dashboard-frontend/vite.config.ts), and the two
PNGs are vite's copy of dashboard-frontend/public/*.png (byte-identical
to the source). None of it is hand-authored, so the whole directory is
untracked rather than partially.

Blobs remain in git history; files remain on disk, just untracked.

* docs(readme): document the required frontend build for pip installs

work/meshai/dashboard/static/ is no longer committed (previous commit),
so the pip install -e . Quick start path now needs an explicit frontend
build step or the dashboard UI silently doesn't exist. Add it, with a
note clarifying the bot/API still work without it -- only the web UI is
affected. Docker is unaffected (already builds the frontend in its own
stage).

* fix(dashboard): log clearly when the built frontend is missing

Previously, if meshai/dashboard/static/ (or its index.html) was absent,
create_app() silently skipped mounting /assets and registering the
root/catch-all routes -- no log, no error. Any request to "/" would
just 404 with FastAPI's generic "Not Found", giving no clue why.

This was latent before (Docker always builds the frontend, and a git
checkout with the artifacts committed always had the directory), but
now that static/ is untracked, a fresh pip install without the frontend
build step will hit this path as its first real-world trigger. Add a
warning log naming the missing path and the exact build command, and
make clear the bot/API are unaffected -- only the dashboard UI is
absent.

* docs(readme): move frontend-build note to root README

work/README.md is about to become a symlink to root README.md on
docs/single-readme. Retarget the frontend-build documentation added in
56eba0f7 from work/README.md to root README.md so it isn't silently
dropped when that symlink lands.

---------

Co-authored-by: Matt Johnson <mj@k7zvx.com>
This commit is contained in:
malice 2026-07-17 14:14:16 -06:00 committed by GitHub
commit 18e9ae9127
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 28 additions and 501 deletions

9
.gitignore vendored
View file

@ -58,8 +58,13 @@ config.yaml
*.pem *.pem
*.key *.key
# Frontend build output (built in Docker via multi-stage) # Frontend build output (built in Docker via multi-stage, or manually for
meshai/dashboard/static/ # the pip install path -- see README "Quick start"). Anchored with the
# work/ prefix: the bare "meshai/dashboard/static/" pattern silently
# stopped matching anything after 2e1fb325 moved the source tree into
# work/, which is how these build artifacts got committed in the first
# place.
work/meshai/dashboard/static/
# Node (frontend deps, reinstalled via package-lock.json / npm ci) # Node (frontend deps, reinstalled via package-lock.json / npm ci)
node_modules/ node_modules/

View file

@ -71,11 +71,17 @@ As you save settings, MeshAI persists them back into `/data` as focused per-doma
```bash ```bash
git clone https://github.com/zvx-echo6/meshai.git git clone https://github.com/zvx-echo6/meshai.git
cd meshai/work cd meshai/work
cd dashboard-frontend && npm ci && npm run build && cd .. # builds the web dashboard — required, see note
pip install -e . pip install -e .
cp config.example.yaml config.yaml # minimal starting point, not exhaustive — see note below cp config.example.yaml config.yaml # minimal starting point, not exhaustive — see note below
meshai meshai
``` ```
> **The frontend build step is required.** `meshai/dashboard/static/` is no longer
> committed to the repo, so skipping it means no dashboard UI is served (the bot and
> API still run fine). Docker users don't need this — the image builds the frontend
> automatically. Requires Node.js/npm.
Unlike Docker, `meshai` won't create a config file for you — it needs one to exist before it will start. `config.example.yaml` bootstraps the basics (connection, LLM backend, bot behavior); once it's running, open `http://localhost:8080` and use the dashboard for everything else. Unlike Docker, `meshai` won't create a config file for you — it needs one to exist before it will start. `config.example.yaml` bootstraps the basics (connection, LLM backend, bot behavior); once it's running, open `http://localhost:8080` and use the dashboard for everything else.
> **Note on `config.example.yaml`:** it documents the legacy single-file schema and is no longer complete — it predates `coverage`, `danger_zones`, `generic_sources`, `meshcore_context`, `commands`, and the current 8-family notification-routing model (`notifications.toggles` / `destinations` / `region_routes`). The legacy single-file loader still works and is fully supported, but the dashboard — backed by the full config schema — is the authoritative way to reach every setting. Don't treat this file as a complete reference. > **Note on `config.example.yaml`:** it documents the legacy single-file schema and is no longer complete — it predates `coverage`, `danger_zones`, `generic_sources`, `meshcore_context`, `commands`, and the current 8-family notification-routing model (`notifications.toggles` / `destinations` / `region_routes`). The legacy single-file loader still works and is fully supported, but the dashboard — backed by the full config schema — is the authoritative way to reach every setting. Don't treat this file as a complete reference.

View file

@ -93,7 +93,7 @@ def create_app() -> FastAPI:
static_dir = Path(__file__).parent / "static" static_dir = Path(__file__).parent / "static"
index_html = static_dir / "index.html" index_html = static_dir / "index.html"
if static_dir.exists(): if static_dir.exists() and index_html.exists():
# Mount /assets for JS, CSS, images # Mount /assets for JS, CSS, images
assets_dir = static_dir / "assets" assets_dir = static_dir / "assets"
if assets_dir.exists(): if assets_dir.exists():
@ -114,6 +114,20 @@ def create_app() -> FastAPI:
@app.get("/") @app.get("/")
async def root(): async def root():
return FileResponse(index_html) return FileResponse(index_html)
else:
# meshai/dashboard/static/ is a build artifact, not committed to the
# repo (see .gitignore) -- it only exists if the frontend has been
# built. Without it there's no route for "/", so requests would
# otherwise 404 with no explanation. Log loudly so a fresh
# `pip install -e .` user knows the bot/API are fine and just the
# dashboard UI needs building.
logger.warning(
"Dashboard UI not found at %s -- the web dashboard will NOT be served "
"(the bot and API are unaffected). Build it with: "
"cd dashboard-frontend && npm ci && npm run build "
"(then restart meshai). Docker images build this automatically.",
index_html,
)
return app return app

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/meshai-icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MeshAI Dashboard</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<script type="module" crossorigin src="/assets/index-FgUiz9s3.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CTVGSJxQ.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 414 KiB