This commit is contained in:
90
AGENTS.md
90
AGENTS.md
@@ -6,9 +6,10 @@ The interface itself speaks five languages (en, es, ca, fr, de), chosen per acco
|
||||
|
||||
```
|
||||
mathew/
|
||||
├── dev.sh # starts/stops both dev servers together
|
||||
├── dev.sh # starts/stops all three services together (lean via docker compose)
|
||||
├── backend/ Express 5 + Mongoose API (port 5000)
|
||||
└── frontend/ Nuxt 4 / Vue 3 wiki UI (port 3000)
|
||||
├── frontend/ Nuxt 4 / Vue 3 wiki UI (port 3000)
|
||||
└── lean/ lean4web editor server — its own Docker image (port 8080)
|
||||
```
|
||||
|
||||
## Running the project
|
||||
@@ -16,13 +17,16 @@ mathew/
|
||||
Requires MongoDB on `localhost:27017` (database `mathew`).
|
||||
|
||||
```bash
|
||||
./dev.sh # both dev servers in foreground (Ctrl+C stops both)
|
||||
./dev.sh # all three services in foreground (Ctrl+C stops all)
|
||||
./dev.sh start|stop|restart|status
|
||||
./dev.sh logs [all|backend|frontend]
|
||||
./dev.sh logs [all|backend|frontend|lean]
|
||||
```
|
||||
|
||||
Or per-service: `npm run dev` inside `backend/` or `frontend/`
|
||||
(backend uses `node --watch`; backend has no build step).
|
||||
(backend uses `node --watch`; backend has no build step). The Lean editor
|
||||
(`/lean`) is the third service: `dev.sh` brings it up through docker compose
|
||||
alongside the npm pair — the first build fetches Mathlib and takes a while,
|
||||
and when docker is unavailable dev.sh says so and still starts the other two.
|
||||
|
||||
Seed sample articles: `npm run seed` in `backend/`.
|
||||
|
||||
@@ -36,7 +40,10 @@ Production (`docker-compose.yml`) points the backend at the LAN MongoDB server
|
||||
with the dev key). The stack's nginx resolves `backend`/`frontend` through Docker's DNS per
|
||||
request, so container recreates cannot leave it on a stale IP.
|
||||
Frontend API URL comes from `NUXT_PUBLIC_API_BASE`
|
||||
(default `http://localhost:5000`, read via `runtimeConfig.public.apiBase`). The frontend image
|
||||
(default `http://localhost:5000`, read via `runtimeConfig.public.apiBase`). The Lean
|
||||
editor's address comes from `NUXT_PUBLIC_LEAN_URL` (default `http://localhost:8080`,
|
||||
read via `runtimeConfig.public.leanUrl`) — on an HTTPS site it must be an https://
|
||||
address too, or the browser blocks it (and the `wss://` derived from it) as mixed content (see `lean/README.md`). The frontend image
|
||||
builds it empty: the browser then calls `/api` on its own origin, which nginx routes to
|
||||
`backend:5000`, while the Nuxt server's own (SSR) `/api` calls go through a `routeRules` proxy
|
||||
aimed at `NUXT_API_PROXY_TARGET` (`https://mathew.aranroig.com` baked in at image build — the
|
||||
@@ -45,6 +52,40 @@ by service name).
|
||||
|
||||
There is **no test suite, linter, or typecheck script** configured — don't invent commands.
|
||||
|
||||
## Lean editor (`lean/`)
|
||||
|
||||
`/lean` is now a **native editor**, not an iframe. The frontend speaks to the lean4web
|
||||
server (`lean/`) directly over its websocket (`ws(s)://<leanUrl>/websocket/<project>`),
|
||||
carrying the Lean 4 **language server protocol** (LSP): the client sends `initialize`,
|
||||
`didOpen`/`didChange`, `$/lean/plainGoal`; the server streams back `publishDiagnostics`
|
||||
and goal answers. That replaces the old frame entirely — the wiki owns the editor (Monaco),
|
||||
its theme (live, same page), and the Goals/Messages pane.
|
||||
|
||||
`lean/Dockerfile` still builds lean4web (upstream's real Lean + Mathlib per session;
|
||||
`--build-arg LEAN4WEB_REF=<tag|branch>` pins it) and runs its websocket server on port 8080;
|
||||
the compose `lean` service runs it. Upstream asks for a dedicated machine, and the image is
|
||||
heavy (Mathlib). It runs `NO_BWRAP=true` — bubblewrap cannot nest in a container, so Docker
|
||||
itself is the sandbox; whoever reaches the port can run Lean. Build/run, TLS, security and
|
||||
projects: `lean/README.md`.
|
||||
|
||||
- `frontend/app/utils/lean/lsp.ts` — a minimal LSP JSON-RPC client over a websocket
|
||||
(request/response pairing, notification dispatch, and auto-ack of the server→client
|
||||
requests a single-document client has no use for). It negotiates `utf-16` positions,
|
||||
matching Monaco's column model.
|
||||
- `frontend/app/utils/lean/lean-language.ts` — registers the `lean4` language with a
|
||||
Monarch tokenizer and Monaco themes rebuilt from the wiki's live tokens: light/dark surfaces
|
||||
plus the chosen `--accent`, so the caret, selection, active line number and keywords follow
|
||||
the accent (`applyLeanTheme()` re-reads the tokens and switches on a live change; themes are
|
||||
named by their palette, so a redefinition never races one Monaco has already cached).
|
||||
- `frontend/app/composables/useLeanSession.ts` — the session: connect to a project, open
|
||||
`Main.lean`, send debounced whole-document `didChange`s, track the cursor for `$/lean/plainGoal`,
|
||||
split diagnostics into editor marks vs. Messages (severity 3 = Lean's `#check`-style info),
|
||||
read elaboration progress. Lives at module scope so the running elaboration outlives the
|
||||
book moving the page between hosts.
|
||||
- `frontend/app/components/LeanWorkbench.vue` — Monaco + the Goals/Messages sidebar; loads
|
||||
Monaco (and the worker) client-side only. Provides completions, hover, `\`→unicode input,
|
||||
and the "open the classic lean4web client" escape link.
|
||||
|
||||
## Backend (`backend/`)
|
||||
|
||||
Plain JavaScript, ESM (`"type": "module"`, `.js` files with relative `.js` import specifiers).
|
||||
@@ -156,7 +197,7 @@ properties so themes swap at runtime via `data-theme`/`data-accent` attributes
|
||||
(set pre-paint by an inline script in `nuxt.config.ts`).
|
||||
|
||||
UI wording is localized with `@nuxtjs/i18n` (`frontend/i18n/`): `i18n.config.ts` plus
|
||||
one JSON catalog per language in `i18n/locales/` (all 350 keys, kept in parity with
|
||||
one JSON catalog per language in `i18n/locales/` (all 405 keys, kept in parity with
|
||||
`en.json`). `strategy: 'no_prefix'` — the interface language never appears in a URL
|
||||
(`/wiki/<lang>/<slug>` is the *article's* language) — with cookie detection
|
||||
(`mathew-locale`, `fallbackLocale: 'en'`) so the server renders in the right language
|
||||
@@ -200,6 +241,26 @@ copy + an `APP_LANGUAGES` entry + the code in the backend's `SUPPORTED_LOCALES`.
|
||||
*calc*, *plot*, *map*) and opening one lays the live surface on a page of the book
|
||||
beside the articles — `ToolPane.vue` is that page (spine, ×, `inert` when not in
|
||||
view), holding the surface extracted as `GraphStage.vue` / `CalculatorStage.vue`.
|
||||
The 3D plotter is a third page of its own, `/calculator3d` — sidebar link
|
||||
and all — drawn by `Calculator3DStage.vue` over `Scene3D.vue`: surfaces
|
||||
z = f(x, y), a sampled mesh projected and shaded by hand onto one canvas,
|
||||
quads laid farthest-first, no 3D library (`compileSurfaceExpression` in
|
||||
`utils/plot-expression.ts` is its algebra). The two calculators share the
|
||||
dock's shapes but never rows — each keeps its own, in localStorage.
|
||||
A name in a field that is none of x, y, a constant or a called function
|
||||
is a slider: a lone `k` or a `k = 2` claims one (plots nothing), and every
|
||||
expression speaking the name answers to its value — the compile pass hands
|
||||
each result its `vars`, and `useVarSliders` (values, each slider anchored
|
||||
under the row that claims it, persistence) and `VarSliders.vue` are shared
|
||||
by both calculators.
|
||||
The Lean editor is a fourth page, `/lean`: `LeanWorkbench.vue` *is* the editor — Monaco
|
||||
(loaded client-side; the `lean4` language and two wiki-matched themes live in
|
||||
`utils/lean/lean-language.ts`) beside a native infoview of Goals, Messages and a status
|
||||
line. `useLeanSession` speaks the Lean language protocol to the lean4web server (`lean/`,
|
||||
address `runtimeConfig.public.leanUrl`) over one websocket, and lives at module scope so a
|
||||
running elaboration survives the book remounting the page. A dead server answers with the
|
||||
unreachable banner and a retry; a status-bar link opens the classic lean4web client in its
|
||||
own tab.
|
||||
`useArticleTabs` files such a page under the identity `page:<name>` and finds it
|
||||
at its own address (`tabAt`/`tabHref` know `toolFromPath`); while its page is
|
||||
open, the plain route hosts defer to the book and draw nothing, and asked plain
|
||||
@@ -349,5 +410,20 @@ copy + an `APP_LANGUAGES` entry + the code in the backend's `SUPPORTED_LOCALES`.
|
||||
the folder tallies come from `/articles/facets` rather than from the cards on
|
||||
screen — counting the loaded batch would let "40 topics" and the tallies
|
||||
grow as the reader scrolls.
|
||||
- **`/lean` speaks to a server outside the stack.** The wiki does not use an iframe: the
|
||||
frontend speaks Lean itself (see the **Lean editor** section) — the browser opens
|
||||
`<leanUrl>/websocket/<project>` (`NUXT_PUBLIC_LEAN_URL`, default `http://localhost:8080`
|
||||
— an address for the browser, not a server-side proxy target to fix up). The Lean server
|
||||
is strict about the handshake: `rootUri` must be a *string* (the server's URI rewriter
|
||||
throws on a null and the message vanishes), and capabilities like `showDocument.support`
|
||||
and `insertTextFormat.valueSet` must be shaped objects — the Lean watchdog quits the
|
||||
session otherwise. The Messages pane reads severity-3 diagnostics (that is where Lean
|
||||
puts `#check` output; there is no `$/lean/plainMessages` anymore). Dev runs the server
|
||||
with `./dev.sh` (via docker compose; or lean4web natively: `NO_BWRAP=true PORT=8080 npm run prod`).
|
||||
On an HTTPS site the address must be https (its `wss://` is derived from it — an `http://`
|
||||
Lean server refuses an https wiki outright).
|
||||
A tool page like this is wired in step: `ToolPage`/`TOOL_PAGE_PATHS`
|
||||
(`utils/routes.ts`), the page file, `TOOL_LABEL_KEYS`, the `ToolPane` branch and spine
|
||||
glyph, the sidebar link, and the `PAGE_TOOLS` entry.
|
||||
- Frontend dev server may fall back to port 3001 if 3000 is taken.
|
||||
- `frontend/types/markdown-it-texmath.d.ts` provides types for the untyped texmath package.
|
||||
|
||||
Reference in New Issue
Block a user