Files
typst-leaf/AGENTS.md
T
nav.sikand b00fe3ec9e Initial scaffold: pnpm workspace monorepo with backend + frontend
- Backend: Express + WebSocket proxy (tsx watch, strict TS, ESM)
- Frontend: React 19 + Vite + Monaco + Tailwind v4 + Tauri v2
- pnpm workspace at root for single-install workflow
- AGENTS.md with architectural constraints and commands
- Removed Tauri greet demo, added minimal App shell
- No external database, Git-as-Database philosophy
2026-07-01 13:23:24 +05:30

51 lines
3.4 KiB
Markdown

# AGENTS.md
Guidelines for AI coding assistants working on typst-leaf.
## Project Context
Self-hosted web IDE for the [Typst](https://typst.app/) typesetting language — a self-hosted "Overleaf" alternative. Built on "Git as the Database": projects are plain folders with `.git`, no external database. Architecture and philosophy are detailed in `VISION.md`.
## Commands
This is a **pnpm workspace** (see `pnpm-workspace.yaml`). Install once from the repo root:
```bash
pnpm install # installs both backend and frontend
pnpm -r typecheck # typecheck ALL workspaces (run before finishing a task)
pnpm --filter typst-leaf-backend dev # backend dev server on http://localhost:4000
pnpm --filter typst-leaf-frontend dev # frontend dev server (Vite)
pnpm --filter typst-leaf-frontend tauri dev # Tauri desktop wrapper (runs Vite first)
```
**No test framework is configured** — the `test` scripts are placeholders. Do not assume one exists.
## Architecture & Boundaries
```
typst-leaf-backend/ Node.js/TS — stateless orchestration: spawns tinymist, proxies WebSockets, REST for files + git
typst-leaf-frontend/ React (Vite) + Monaco — the IDE SPA; also contains src-tauri/ for the desktop build
```
* **Backend** (`typst-leaf-backend/`): ESM (`"type": "module"`), strict TS with `noUncheckedIndexedAccess`. Entry: `src/index.ts`. Dev via `tsx watch`; build via `tsc``dist/`. Uses `express` + `ws` + `simple-git` + `execa` + `zod`.
* **Frontend** (`typst-leaf-frontend/`): React 19 + Vite. Monaco Editor wired to LSP via `monaco-languageclient` + `vscode-ws-jsonrpc`. Styling is **Tailwind v4** via the `@tailwindcss/vite` plugin (import with `@import "tailwindcss"`; there is no `tailwind.config.js`).
* **Tauri v2** lives at `typst-leaf-frontend/src-tauri/`. It shells out to `pnpm dev`/`pnpm build` and serves `../dist`.
* **Data plane:** `ws://localhost:4000/lsp` (LSP), `ws://localhost:4000/preview` (SVG stream).
## Critical Constraints (do NOT violate)
1. **Never re-implement Typst/LSP logic in TypeScript.** Spawn `tinymist` as a child process and pipe WebSocket messages straight to its stdio. The backend is a thin proxy.
2. **Never use PDF.js.** The preview renders **SVG** streamed from tinymist (selectable text, instant diffs, no binary PDFs).
3. **Path duality:** the frontend sees *virtual paths*; the backend sees *absolute OS paths* under the projects root. Keep the mapping explicit — this is a frequent source of bugs.
4. **No polling** for file or preview changes. Drive updates from LSP/WebSocket events only.
5. **Monaco LSP lifecycle is fragile.** Always dispose the languageclient + WebSocket on component unmount to avoid leaking duplicate socket connections.
6. **Browser-first.** The app must run in a generic browser. Guard any Tauri-only API behind a `window.__TAURI__` check; do not rely on it exclusively.
7. **No databases.** State = filesystem; history = `.git`. Collaboration is Git (commit/push/pull in the UI), not OT/CRDTs.
## Port Gotcha
The frontend dev server is **port 1420** (`strictPort: true`, mandated by Tauri) — **not** 3000 as `README.md` states. Backend is port 4000. `README.md` is stale on this point; trust `vite.config.ts`.
## Code Style
* TypeScript strict mode in both packages. **No `any`.** Validate at API boundaries with `zod`.
* Prefer `async/await` over raw Promises.
* Comment complex logic around WebSocket message passing and process spawning.