docs: refresh README, architecture, spec and add agent teams proposal
Browse files- README: align env var table with real backend (OPENROUTER_API_KEY, HF_DATASET_ID, SPACE_ID,
PUBLISH_BASE_URL, ENABLE_PDF, OAUTH_SCOPES) and fix prerequisites
- ARCHITECTURE / SPECIFICATION: describe the new transformer pipeline, embed studio flow,
mobile TOC + CommentPopover; drop the deleted CommentsSidebar reference
- TESTS: announce the Playwright E2E suite as part of the stack and add 4.1.4 for the
upload rate limiter; note the split between fast hermetic suite and opt-in E2E
- Add AGENT_TEAMS_PROPOSAL.md to track the upcoming multi-agent collaboration design
Made-with: Cursor
- README.md +155 -13
- docs/AGENT_TEAMS_PROPOSAL.md +186 -0
- docs/ARCHITECTURE.md +40 -12
- docs/SPECIFICATION.md +16 -11
README.md
CHANGED
|
@@ -13,25 +13,167 @@ hf_oauth_scopes:
|
|
| 13 |
|
| 14 |
# Research Article Template Editor
|
| 15 |
|
| 16 |
-
|
| 17 |
|
| 18 |
-
|
| 19 |
|
| 20 |
-
|
| 21 |
-
- Rich text: headings, bold, italic, lists, blockquotes, code blocks
|
| 22 |
-
- Export to MDX format
|
| 23 |
-
- Dark theme
|
| 24 |
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
```bash
|
| 28 |
-
#
|
| 29 |
-
cd backend
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
-
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
| 33 |
```
|
| 34 |
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
-
|
|
|
|
| 13 |
|
| 14 |
# Research Article Template Editor
|
| 15 |
|
| 16 |
+
A collaborative, real-time editor for web-native scientific articles. It lets multiple authors co-write a paper with rich text, math, citations, figures and interactive D3 embeds, then publishes the result as a static HTML page (or a PDF) aligned with the [research-article-template](https://github.com/huggingface/research-article-template).
|
| 17 |
|
| 18 |
+

|
| 19 |
|
| 20 |
+
## What it gives you
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
+
- **Real-time collaboration** over WebSocket (Y.js + Hocuspocus), with visible cursors and per-user selection colors
|
| 23 |
+
- **Rich article authoring**: headings, lists, tables, code blocks with syntax highlighting, LaTeX math (KaTeX), footnotes, sidenotes, block quotes, callouts
|
| 24 |
+
- **Research-specific blocks**: citations + bibliography (BibTeX), figures with captions, stacks / wide / full-width layouts, glossary terms, Mermaid/Wardley/architecture diagrams
|
| 25 |
+
- **Interactive D3 embeds** authored inline: each embed is a self-contained HTML file the editor can generate and iterate on via an **AI-assisted "embed studio"**
|
| 26 |
+
- **Comments & discussion** anchored on any selection
|
| 27 |
+
- **Slash menu** (`/`) and drag/drop block handles, in the spirit of Notion
|
| 28 |
+
- **Click-to-edit frontmatter**: title, subtitle, authors, affiliations, links, banner color
|
| 29 |
+
- **Publishing pipeline**: one-click export to a standalone static HTML bundle, plus PDF generation (Puppeteer)
|
| 30 |
+
- **Persistence**:
|
| 31 |
+
- Local mode: documents stored on disk under `DATA_DIR`
|
| 32 |
+
- HF mode: documents pushed/pulled from a Hugging Face dataset via OAuth
|
| 33 |
+
- **Dark mode**, responsive layout (TOC drawer on mobile), live table of contents with scroll-spy
|
| 34 |
+
- **AI chat side-panel** that can edit the article via structured tool calls (agent loop over the current TipTap doc)
|
| 35 |
+
|
| 36 |
+
## Stack
|
| 37 |
+
|
| 38 |
+
| Layer | Tech |
|
| 39 |
+
|---|---|
|
| 40 |
+
| Editor | React 18, TypeScript, TipTap v3, ProseMirror |
|
| 41 |
+
| Collaboration | Y.js, Hocuspocus (WebSocket), y-tiptap |
|
| 42 |
+
| Backend | Node.js, Express, Vite (dev proxy), Hocuspocus server |
|
| 43 |
+
| Publishing | Custom TipTap-JSON → HTML renderer, Puppeteer for PDF |
|
| 44 |
+
| AI | Vercel AI SDK v6 (`ai`, `@ai-sdk/react`), streaming tool calls |
|
| 45 |
+
| Styling | Plain CSS with custom properties, no framework |
|
| 46 |
+
| Storage | Local FS or Hugging Face datasets (via `@huggingface/hub`) |
|
| 47 |
+
| Container | Single-image Docker build, runs on port 8080 |
|
| 48 |
+
|
| 49 |
+
Around **3.6k LOC backend** and **9.5k LOC frontend** (TypeScript/TSX, excluding generated code).
|
| 50 |
+
|
| 51 |
+
## Repo layout
|
| 52 |
+
|
| 53 |
+
```
|
| 54 |
+
collab-editor/
|
| 55 |
+
├── backend/ # Express + Hocuspocus server, publisher, AI agent routes
|
| 56 |
+
│ └── src/
|
| 57 |
+
│ ├── server.ts # Entry point
|
| 58 |
+
│ ├── create-app.ts # App factory (routes, middleware, Hocuspocus)
|
| 59 |
+
│ ├── publisher/ # TipTap-JSON → HTML + PDF
|
| 60 |
+
│ ├── agent/ # LLM agent (tool calls over the doc)
|
| 61 |
+
│ ├── shared/ # Component defs shared with the frontend
|
| 62 |
+
│ └── hf-storage.ts # HF dataset sync
|
| 63 |
+
├── frontend/ # Vite + React + TipTap editor
|
| 64 |
+
│ └── src/
|
| 65 |
+
│ ├── App.tsx # Top-level shell
|
| 66 |
+
│ ├── editor/ # TipTap editor + extensions + components
|
| 67 |
+
│ ├── components/ # Shared UI pieces (TOC, Chat, Dialog, ...)
|
| 68 |
+
│ ├── hooks/ # React hooks (agent chat, selection, ...)
|
| 69 |
+
│ ├── styles/ # CSS layers (see docs/ARCHITECTURE.md)
|
| 70 |
+
│ └── utils/
|
| 71 |
+
├── docs/
|
| 72 |
+
│ ├── ARCHITECTURE.md # Deep dive on layers, data flow, CSS
|
| 73 |
+
│ ├── SPECIFICATION.md # Feature spec and contracts
|
| 74 |
+
│ ├── TESTS.md # Testing strategy
|
| 75 |
+
│ └── embed-studio.md # How the AI-authored embeds pipeline works
|
| 76 |
+
└── Dockerfile # Production multi-stage build
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for a diagram and the full tour.
|
| 80 |
+
|
| 81 |
+
## Getting started
|
| 82 |
+
|
| 83 |
+
### Prerequisites
|
| 84 |
+
|
| 85 |
+
- Node.js 20+
|
| 86 |
+
- An OpenRouter API key if you want the AI features (embed studio, chat agent)
|
| 87 |
+
- A Hugging Face OAuth app (client id/secret) if you want login + HF dataset persistence
|
| 88 |
+
|
| 89 |
+
### Local development
|
| 90 |
+
|
| 91 |
+
Backend and frontend run as two separate processes in dev (Vite proxies `/api`, `/collab`, `/uploads`, `/published`, `/oauth`, `/auth` to the backend).
|
| 92 |
|
| 93 |
```bash
|
| 94 |
+
# terminal 1 — backend (Express + Hocuspocus on :8080)
|
| 95 |
+
cd backend
|
| 96 |
+
cp .env.example .env # fill in HF_TOKEN, OPENAI_API_KEY, ...
|
| 97 |
+
npm install
|
| 98 |
+
npm run dev
|
| 99 |
+
|
| 100 |
+
# terminal 2 — frontend (Vite on :5678)
|
| 101 |
+
cd frontend
|
| 102 |
+
npm install
|
| 103 |
+
npm run dev
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
Then open http://localhost:5678. Open a second tab or browser to see collaboration in action.
|
| 107 |
+
|
| 108 |
+
### Production (Docker / HF Spaces)
|
| 109 |
|
| 110 |
+
The `Dockerfile` builds both frontend and backend into a single image listening on port 8080. This is the image used by the Hugging Face Space.
|
| 111 |
+
|
| 112 |
+
```bash
|
| 113 |
+
docker build -t collab-editor .
|
| 114 |
+
docker run -p 8080:8080 --env-file backend/.env collab-editor
|
| 115 |
```
|
| 116 |
|
| 117 |
+
Then open http://localhost:8080.
|
| 118 |
+
|
| 119 |
+
## Scripts
|
| 120 |
+
|
| 121 |
+
### Backend (`cd backend`)
|
| 122 |
+
|
| 123 |
+
| Command | What it does |
|
| 124 |
+
|---|---|
|
| 125 |
+
| `npm run dev` | Start Express + Hocuspocus in watch mode |
|
| 126 |
+
| `npm run build` | Compile TypeScript to `dist/` |
|
| 127 |
+
| `npm start` | Run the compiled server |
|
| 128 |
+
| `npm run test` | Unit + integration tests (Vitest) |
|
| 129 |
+
| `npm run test:e2e` | End-to-end tests (Playwright) |
|
| 130 |
+
|
| 131 |
+
### Frontend (`cd frontend`)
|
| 132 |
+
|
| 133 |
+
| Command | What it does |
|
| 134 |
+
|---|---|
|
| 135 |
+
| `npm run dev` | Start Vite dev server on :5678 |
|
| 136 |
+
| `npm run build` | Production bundle to `dist/` |
|
| 137 |
+
| `npm run preview` | Preview the built bundle |
|
| 138 |
+
| `npm run test` | Unit tests (Vitest) |
|
| 139 |
+
| `npm run typecheck` | `tsc --noEmit` on the whole frontend |
|
| 140 |
+
|
| 141 |
+
## Environment variables
|
| 142 |
+
|
| 143 |
+
Copy `backend/.env.example` to `backend/.env` and fill the relevant values. Key ones:
|
| 144 |
+
|
| 145 |
+
| Variable | Purpose |
|
| 146 |
+
|---|---|
|
| 147 |
+
| `OAUTH_CLIENT_ID` / `OAUTH_CLIENT_SECRET` | HF OAuth app for user login (required to edit when running on a Space) |
|
| 148 |
+
| `OAUTH_SCOPES` | OAuth scopes (default `openid profile`) |
|
| 149 |
+
| `OPENROUTER_API_KEY` | API key used by the AI agent (chat panel + embed studio) |
|
| 150 |
+
| `OPENROUTER_MODEL` | Override the default OpenRouter model id |
|
| 151 |
+
| `HF_TOKEN` | Server-side Hugging Face token (fallback when no user OAuth token is present) |
|
| 152 |
+
| `HF_DATASET_ID` | Target HF dataset repo for document persistence (when not running on a Space) |
|
| 153 |
+
| `SPACE_ID` / `SPACE_HOST` | Auto-set by HF Spaces; drive dataset id + secure cookies in production |
|
| 154 |
+
| `DATA_DIR` | Where documents, uploads and published bundles are stored on disk (default: `./data`) |
|
| 155 |
+
| `PUBLISH_BASE_URL` | Absolute base URL used when publishing (defaults to `http://127.0.0.1:${PORT}`) |
|
| 156 |
+
| `ENABLE_PDF` | Set to `false` to disable Playwright-based PDF export |
|
| 157 |
+
| `PORT` | Server port (default 8080) |
|
| 158 |
+
|
| 159 |
+
## Testing
|
| 160 |
+
|
| 161 |
+
- **Backend unit tests**: Vitest covers the publisher (HTML renderer, frontmatter, bibliography), storage, auth utilities.
|
| 162 |
+
- **Backend E2E**: Playwright drives the full editor against a real backend.
|
| 163 |
+
- **Frontend unit tests**: Vitest covers chat persistence and a handful of utilities.
|
| 164 |
+
- **Type checking**: `npm run typecheck` in both workspaces.
|
| 165 |
+
|
| 166 |
+
See [`docs/TESTS.md`](docs/TESTS.md) for the current strategy and gaps.
|
| 167 |
+
|
| 168 |
+
## Known technical debt
|
| 169 |
+
|
| 170 |
+
These are tracked explicitly so new contributors don't trip on them:
|
| 171 |
+
|
| 172 |
+
- **`useAgentChat` / `useEmbedChat` still lack dedicated unit tests**; the rest of the stores (frontmatter, comments, embeds) are now covered.
|
| 173 |
+
- **Bundle size warning**: the frontend bundle is over the 500 kB Vite warning threshold. Code-splitting the Mermaid / KaTeX / D3 stacks via dynamic imports would help.
|
| 174 |
+
- **`addToolOutput` typing**: the ai-sdk v6 `ChatAddToolOutputFunction` is a generic over the tool name union. We currently cast to a plain signature at the two call sites because we don't export a typed tool registry yet.
|
| 175 |
+
- **`backend/src/publisher/html-renderer.ts` is ~1000 LOC**: a per-node-type registry would make it more maintainable.
|
| 176 |
+
|
| 177 |
+
## License
|
| 178 |
|
| 179 |
+
Follow the upstream [research-article-template](https://github.com/huggingface/research-article-template) license.
|
docs/AGENT_TEAMS_PROPOSAL.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Proposition - Passer d'un agent unique à une équipe d'agents
|
| 2 |
+
|
| 3 |
+
> Réflexion inspirée de l'article [The Collaboration Gap](https://robotscooking.substack.com/p/the-collaboration-gap) (Adam Hyde, 2026) appliquée à `collab-editor`.
|
| 4 |
+
|
| 5 |
+
## 1. Constat sur l'état actuel
|
| 6 |
+
|
| 7 |
+
Le `collab-editor` est aujourd'hui structuré autour de **deux agents isolés** :
|
| 8 |
+
|
| 9 |
+
| Agent | Fichier | Rôle |
|
| 10 |
+
|---|---|---|
|
| 11 |
+
| Article agent | `backend/src/agent/chat.ts` + `frontend/src/hooks/useAgentChat.ts` | Édite le TipTap doc via `applyDiff` / `replaceSelection` / `insertAtCursor` |
|
| 12 |
+
| Embed agent | `backend/src/agent/embed-chat.ts` + `frontend/src/hooks/useEmbedChat.ts` | Génère les embeds D3 |
|
| 13 |
+
|
| 14 |
+
Les deux ne se parlent pas. Ils ne partagent pas de contexte. L'utilisateur est le seul "orchestrateur", à la main, en switchant d'interface.
|
| 15 |
+
|
| 16 |
+
C'est exactement le pattern "one human, one AI, one task" que l'article pointe comme limitant.
|
| 17 |
+
|
| 18 |
+
## 2. Ce qu'on a déjà gratuitement (et que la plupart des setups multi-agents n'ont pas)
|
| 19 |
+
|
| 20 |
+
| Brique | Fichier | Pourquoi c'est un atout |
|
| 21 |
+
|---|---|---|
|
| 22 |
+
| État partagé versionné (CRDT) | Y.js + Hocuspocus | C'est LE "shared board" de l'article, déjà construit, déjà résolveur de conflits |
|
| 23 |
+
| Canal de messages ancrés | `frontend/src/editor/comments.ts` + `CommentsSidebar.tsx` | Communication latérale entre agents, visible par l'humain |
|
| 24 |
+
| Undo groupé par tour | `UndoManager` + `startAgentBatch` | Rollback atomique d'une action d'équipe |
|
| 25 |
+
| Tool calls structurés | `backend/src/agent/tools.ts` | Protocole déjà formalisé |
|
| 26 |
+
| Frontmatter store réactif | `frontend/src/editor/frontmatter/frontmatter-store.ts` | État structuré séparé du corps, parfait pour un agent dédié |
|
| 27 |
+
|
| 28 |
+
**Traduction** : on est mieux placés que Pure.Science pour implémenter ce que décrit Adam Hyde, parce que notre "bubble" existe déjà côté humain.
|
| 29 |
+
|
| 30 |
+
## 3. Proposition d'architecture - 5 rôles
|
| 31 |
+
|
| 32 |
+
Inspirée directement de Pure.Science (Wax, Ketty, Coco, Paige, Koda), mais adaptée à l'écriture scientifique web-native.
|
| 33 |
+
|
| 34 |
+
### 3.1. Rôles
|
| 35 |
+
|
| 36 |
+
| Agent | Rôle | Outils autorisés | Zones d'écriture |
|
| 37 |
+
|---|---|---|---|
|
| 38 |
+
| **Scout** | Topic Strategist : cadre le papier, propose l'angle | `setFrontmatterDraft`, `proposeOutline` (commentaire) | Commentaires uniquement |
|
| 39 |
+
| **Archi** | Outliner / Structurer : gère TOC, hiérarchie, sections | `applyDiff` sur headings, `insertSection` | Headings, structure |
|
| 40 |
+
| **Scribe** | Writer : rédige les paragraphes | `applyDiff`, `insertAtCursor` | Corps du texte |
|
| 41 |
+
| **Biblio** | Literature Retriever : cherche des refs, pose des citations | `addCitation`, `addBibEntry`, `commentSuggestion` | Bibliography.bib + balises `[@key]` |
|
| 42 |
+
| **Critic** | QA / Reviewer : relit, pointe incohérences, passe des commentaires | `comment`, `resolveComment`, `flagInconsistency` | Commentaires uniquement (read-only sur le doc) |
|
| 43 |
+
|
| 44 |
+
**Point crucial** : seuls `Archi` et `Scribe` touchent au texte. `Critic` **ne peut pas éditer**, il commente - ça force la friction que décrit l'article et évite le "yes-man loop" des LLMs.
|
| 45 |
+
|
| 46 |
+
### 3.2. Orchestrateur
|
| 47 |
+
|
| 48 |
+
Un agent léger côté backend (nouveau fichier `backend/src/agent/orchestrator.ts`) qui :
|
| 49 |
+
|
| 50 |
+
1. Reçoit le message de l'humain
|
| 51 |
+
2. Lit l'état du doc (+ frontmatter + commentaires ouverts)
|
| 52 |
+
3. Décide quel(s) agent(s) réveiller et dans quel ordre
|
| 53 |
+
4. Tient un journal de tâches visible (équivalent du "board" dans l'article)
|
| 54 |
+
|
| 55 |
+
L'orchestrateur n'édite jamais. Il **dispatche** et **attend**. Comme le facilitateur d'un Book Sprint.
|
| 56 |
+
|
| 57 |
+
### 3.3. Code de conduite partagé
|
| 58 |
+
|
| 59 |
+
Un prompt-système commun (nouveau `backend/src/agent/team-code-of-conduct.ts`) injecté dans **tous** les agents :
|
| 60 |
+
|
| 61 |
+
```md
|
| 62 |
+
1. Avant toute action, lis le board (commentaires ouverts + journal orchestrateur).
|
| 63 |
+
2. Reste dans ton rôle. Si une tâche sort de ton périmètre, ping l'agent compétent via un commentaire typé.
|
| 64 |
+
3. N'écrase pas le travail d'un autre agent sans laisser un commentaire justifiant le changement.
|
| 65 |
+
4. Les désaccords se résolvent par commentaire ancré, pas par écrasement silencieux.
|
| 66 |
+
5. Sois concis. Un message = une intention.
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
Directement dérivé du "code of conduct" Pure.Science.
|
| 70 |
+
|
| 71 |
+
## 4. Communication latérale - piggyback sur les commentaires
|
| 72 |
+
|
| 73 |
+
Plutôt qu'un bus de messages séparé, on étend le système de commentaires existant avec un champ `author` et `audience` :
|
| 74 |
+
|
| 75 |
+
```ts
|
| 76 |
+
interface AgentComment {
|
| 77 |
+
author: "scout" | "archi" | "scribe" | "biblio" | "critic" | "human";
|
| 78 |
+
audience: Array<"scout" | "archi" | "scribe" | "biblio" | "critic" | "human">;
|
| 79 |
+
kind: "suggestion" | "question" | "blocker" | "task";
|
| 80 |
+
anchor: { from: number; to: number };
|
| 81 |
+
body: string;
|
| 82 |
+
}
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
Bénéfices :
|
| 86 |
+
- L'humain voit **tout** dans la sidebar existante (`CommentsSidebar.tsx`)
|
| 87 |
+
- Les agents s'adressent à un autre agent via `audience: ["scribe"]`
|
| 88 |
+
- Rien à construire côté infra, juste étendre le schema
|
| 89 |
+
|
| 90 |
+
## 5. UI - rendre l'équipe visible
|
| 91 |
+
|
| 92 |
+
L'article insiste sur le fait que **la valeur de la collab est invisible si on ne la montre pas**. Proposition côté UI :
|
| 93 |
+
|
| 94 |
+
### 5.1. Team activity timeline
|
| 95 |
+
|
| 96 |
+
Un petit panneau dans `TopBar.tsx` ou sous le chat :
|
| 97 |
+
|
| 98 |
+
```
|
| 99 |
+
[Archi] → created section "Methodology" 2s ago
|
| 100 |
+
[Biblio] → suggested 3 citations in §2 5s ago
|
| 101 |
+
[Critic] → flagged: unsupported claim in §3 8s ago
|
| 102 |
+
[Scribe] → drafted paragraph in §1 12s ago
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
### 5.2. Curseurs colorés par agent
|
| 106 |
+
|
| 107 |
+
On a déjà les curseurs multi-utilisateurs via `collaboration-cursor-v3.ts`. Chaque agent devient un "utilisateur virtuel" avec sa couleur et son nom de rôle. L'humain **voit en direct** où chaque agent travaille. Zero nouvelle infra.
|
| 108 |
+
|
| 109 |
+
### 5.3. Quick actions par rôle
|
| 110 |
+
|
| 111 |
+
Remplacer le `sendQuickAction` générique de `useAgentChat.ts` par un sélecteur de rôle :
|
| 112 |
+
|
| 113 |
+
```
|
| 114 |
+
Ask [ Scribe ▾ ] to: [ rewrite this paragraph ]
|
| 115 |
+
```
|
| 116 |
+
|
| 117 |
+
## 6. Plan d'implémentation progressif
|
| 118 |
+
|
| 119 |
+
Par ordre de ROI, du plus petit au plus gros.
|
| 120 |
+
|
| 121 |
+
### Étape 1 - Split sémantique sans nouvelle infra (2-3j)
|
| 122 |
+
|
| 123 |
+
- Spécialiser le prompt actuel : le SYSTEM prompt passe de "tu es un assistant qui édite" à "tu es le Scribe, tu écris les paragraphes".
|
| 124 |
+
- Ajouter un prompt `Critic` qui ne fait QUE passer des commentaires (pas de tool d'édition).
|
| 125 |
+
- UI : un dropdown "Talk to [ Scribe / Critic ]".
|
| 126 |
+
|
| 127 |
+
Valeur : on valide l'hypothèse qu'un agent read-only qui commente améliore la qualité perçue, avant de construire l'orchestration.
|
| 128 |
+
|
| 129 |
+
### Étape 2 - Curseurs agents + timeline (2j)
|
| 130 |
+
|
| 131 |
+
- Chaque agent = user Y.js virtuel avec couleur.
|
| 132 |
+
- Timeline agrégée depuis les tool calls loggés.
|
| 133 |
+
|
| 134 |
+
Valeur : rend la collaboration lisible, c'est le point central d'Adam Hyde.
|
| 135 |
+
|
| 136 |
+
### Étape 3 - Biblio agent autonome (3-4j)
|
| 137 |
+
|
| 138 |
+
- Outils `addCitation`, `searchArxiv`, `addBibEntry`.
|
| 139 |
+
- Déclenchement automatique quand `Scribe` écrit une affirmation factuelle (via tool `requestCitation`).
|
| 140 |
+
|
| 141 |
+
Valeur : premier cas de communication latérale agent→agent concrète.
|
| 142 |
+
|
| 143 |
+
### Étape 4 - Orchestrateur (5-7j)
|
| 144 |
+
|
| 145 |
+
- Nouveau route `/api/orchestrate` qui dispatche plutôt que de `/api/chat` directement.
|
| 146 |
+
- Board visible dans le chat.
|
| 147 |
+
|
| 148 |
+
Valeur : vrai multi-agent, mais seulement une fois les étapes 1-3 validées.
|
| 149 |
+
|
| 150 |
+
### Étape 5 - Scout (cadrage initial) (3j)
|
| 151 |
+
|
| 152 |
+
- Agent qui intervient uniquement au début d'un nouveau doc, à partir d'un prompt court "je veux écrire sur X".
|
| 153 |
+
- Génère frontmatter + TOC + commentaires de cadrage.
|
| 154 |
+
|
| 155 |
+
Valeur : onboarding d'un nouvel article 10x plus fluide.
|
| 156 |
+
|
| 157 |
+
## 7. Métrique de succès
|
| 158 |
+
|
| 159 |
+
Adam Hyde souligne qu'on ne sait pas benchmarker la collaboration. Proposition de 3 mesures simples et propres à l'éditeur :
|
| 160 |
+
|
| 161 |
+
| Métrique | Comment | Pourquoi |
|
| 162 |
+
|---|---|---|
|
| 163 |
+
| **Commentaires résolus par session** | Compteur via le store de commentaires | Proxy de la qualité de la friction |
|
| 164 |
+
| **Ratio d'édits rollback par l'humain** | Undo après action agent / total actions agent | Mesure l'alignement |
|
| 165 |
+
| **Temps médian d'un article jusqu'à "publish"** | Log `published_at - created_at` côté backend | Mesure l'effet global |
|
| 166 |
+
|
| 167 |
+
Pas de benchmark LLM abstrait : on mesure **sur le produit**.
|
| 168 |
+
|
| 169 |
+
## 8. Risques et limites
|
| 170 |
+
|
| 171 |
+
- **Coût tokens ×N** : chaque tour peut réveiller 2-3 agents. À mitiger avec un routing intelligent côté orchestrateur (ne pas réveiller `Biblio` si le message est "fix grammaire").
|
| 172 |
+
- **LLMs d'accord avec tout** : le rôle `Critic` ne marche que si le prompt force la contradiction explicite. À itérer avec des exemples few-shot.
|
| 173 |
+
- **UX du bruit** : si les 5 agents commentent en permanence, la sidebar devient illisible. Prévoir un mode "muet par défaut, opt-in par rôle".
|
| 174 |
+
- **Complexité de debug** : logger impérativement le journal orchestrateur pour pouvoir rejouer une session.
|
| 175 |
+
|
| 176 |
+
## 9. Ce que ça apporte à ton produit
|
| 177 |
+
|
| 178 |
+
Aujourd'hui `collab-editor` est "un Notion-like pour papiers scientifiques avec un AI assistant". C'est bien, mais une dizaine de produits font ça.
|
| 179 |
+
|
| 180 |
+
Avec cette architecture, tu deviens **le premier éditeur scientifique où une équipe d'agents spécialisés co-écrit avec l'humain**, en s'appuyant sur l'infra temps-réel Y.js que tu as déjà. C'est une proposition produit claire et différenciante, directement alignée avec la thèse de l'article :
|
| 181 |
+
|
| 182 |
+
> "Les organisations qui investissent dans l'architecture de collaboration avec le même sérieux qu'elles investissent dans la capacité des modèles produiront de meilleurs résultats."
|
| 183 |
+
|
| 184 |
+
## 10. Prochaine étape concrète suggérée
|
| 185 |
+
|
| 186 |
+
Commencer par **l'étape 1** : forker `useAgentChat` en `useScribeChat` + `useCriticChat`, avec un simple toggle d'UI. C'est 2 jours de boulot, ça valide ou invalide l'hypothèse avant d'engager l'orchestrateur.
|
docs/ARCHITECTURE.md
CHANGED
|
@@ -29,37 +29,57 @@ The collab-editor is a collaborative article editor built for Hugging Face Space
|
|
| 29 |
|
| 30 |
| Path | Description |
|
| 31 |
|------|-------------|
|
| 32 |
-
| `backend/src/server.ts` |
|
|
|
|
| 33 |
| `backend/src/publisher/` | HTML rendering, PDF generation, bibliography formatting |
|
| 34 |
| `backend/src/publisher/html-renderer.ts` | Converts TipTap JSON to static HTML page |
|
| 35 |
| `backend/src/publisher/extensions.ts` | Server-side TipTap extensions (mirrors frontend) |
|
| 36 |
| `backend/src/shared/component-defs.ts` | Shared component definitions (single source of truth) |
|
|
|
|
|
|
|
|
|
|
| 37 |
| `frontend/src/editor/` | TipTap editor, toolbars, components |
|
| 38 |
| `frontend/src/editor/components/registry.ts` | Component registry (imports from shared defs) |
|
| 39 |
| `frontend/src/styles/` | All CSS files |
|
| 40 |
-
| `frontend/src/styles/_publisher.css` | Publisher-only CSS (injected into static HTML) |
|
| 41 |
-
| `frontend/src/styles/_ui.css` | Editor chrome CSS (buttons, dialogs, drawers) |
|
| 42 |
|
| 43 |
## Styling architecture
|
| 44 |
|
| 45 |
### CSS layers
|
| 46 |
|
| 47 |
-
The project uses
|
| 48 |
|
| 49 |
-
1. **Template
|
| 50 |
-
- Defines the article's visual identity
|
| 51 |
- Uses CSS custom properties (`--text-color`, `--surface-bg`, `--primary-color`, etc.)
|
|
|
|
| 52 |
- Shared between the editor preview and the published output
|
| 53 |
|
| 54 |
-
2. **Editor chrome
|
| 55 |
-
- Styles the editor UI:
|
| 56 |
- Uses `--ed-*` custom properties for the dark editor theme
|
| 57 |
- Only loaded in the editor, never in published output
|
| 58 |
|
| 59 |
-
3. **
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
- Styles specific to the published static HTML page
|
| 61 |
-
-
|
| 62 |
-
- Only injected by the HTML renderer, never loaded in the editor
|
| 63 |
|
| 64 |
### No CSS-in-JS
|
| 65 |
|
|
@@ -139,9 +159,15 @@ The `postProcess()` function uses `linkedom` for DOM manipulation instead of reg
|
|
| 139 |
|
| 140 |
`GET /api/preview/:docName` renders the HTML without saving or uploading. Useful for testing the publisher pipeline.
|
| 141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
## Testing
|
| 143 |
|
| 144 |
-
Tests use Vitest. Run with `npm test` from `backend/`.
|
| 145 |
|
| 146 |
| Test file | What it covers |
|
| 147 |
|-----------|----------------|
|
|
@@ -152,3 +178,5 @@ Tests use Vitest. Run with `npm test` from `backend/`.
|
|
| 152 |
| `tests/utils.test.ts` | Path sanitization utilities |
|
| 153 |
| `tests/auth.test.ts` | Token extraction, OAuth configuration |
|
| 154 |
| `tests/hf-storage.test.ts` | HF dataset storage configuration |
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
| Path | Description |
|
| 31 |
|------|-------------|
|
| 32 |
+
| `backend/src/server.ts` | Entry point: imports `createApp()`, starts listener, signal handlers |
|
| 33 |
+
| `backend/src/create-app.ts` | Express app factory: routes, Hocuspocus, WebSocket, middleware |
|
| 34 |
| `backend/src/publisher/` | HTML rendering, PDF generation, bibliography formatting |
|
| 35 |
| `backend/src/publisher/html-renderer.ts` | Converts TipTap JSON to static HTML page |
|
| 36 |
| `backend/src/publisher/extensions.ts` | Server-side TipTap extensions (mirrors frontend) |
|
| 37 |
| `backend/src/shared/component-defs.ts` | Shared component definitions (single source of truth) |
|
| 38 |
+
| `backend/src/utils.ts` | Shared utilities: `docPath()`, `sanitizeName()`, injectable `DATA_DIR` |
|
| 39 |
+
| `backend/src/auth.ts` | OAuth flow, token extraction, user resolution |
|
| 40 |
+
| `backend/src/hf-storage.ts` | HF dataset sync (push/pull documents and assets) |
|
| 41 |
| `frontend/src/editor/` | TipTap editor, toolbars, components |
|
| 42 |
| `frontend/src/editor/components/registry.ts` | Component registry (imports from shared defs) |
|
| 43 |
| `frontend/src/styles/` | All CSS files |
|
|
|
|
|
|
|
| 44 |
|
| 45 |
## Styling architecture
|
| 46 |
|
| 47 |
### CSS layers
|
| 48 |
|
| 49 |
+
The project uses five CSS layers, loaded in this order by `main.tsx`:
|
| 50 |
|
| 51 |
+
1. **Template foundation** (`_variables.css`, `_reset.css`, `_base.css`, `_layout.css`, `_print.css`, `components/*`)
|
| 52 |
+
- Defines the article's visual identity (typography, grid, components)
|
| 53 |
- Uses CSS custom properties (`--text-color`, `--surface-bg`, `--primary-color`, etc.)
|
| 54 |
+
- Layout tokens centralize grid math (`--layout-toc-width`, `--layout-content-width`, `--layout-gap`, breakpoints)
|
| 55 |
- Shared between the editor preview and the published output
|
| 56 |
|
| 57 |
+
2. **Editor chrome** (`_ui.css`)
|
| 58 |
+
- Styles the editor UI: top-bar, sidebars, dialogs, chat panel, embed studio
|
| 59 |
- Uses `--ed-*` custom properties for the dark editor theme
|
| 60 |
- Only loaded in the editor, never in published output
|
| 61 |
|
| 62 |
+
3. **Design tokens** (`tokens.css`)
|
| 63 |
+
- Light/dark theming tokens for both editor and article
|
| 64 |
+
- Text, background, border, accent, code highlighting, danger, shadows
|
| 65 |
+
- Supports `data-theme` attribute and `prefers-color-scheme` media query
|
| 66 |
+
- Shared between editor and published output (injected by publisher)
|
| 67 |
+
|
| 68 |
+
4. **Shared article styles** (`article.css`, `toc.css`)
|
| 69 |
+
- Article content styles shared between editor preview and published output
|
| 70 |
+
- `article.css` includes wrapper components (Note, Stack, Quote, Sidenote...), with editor-specific variants scoped by `.editor-app`
|
| 71 |
+
|
| 72 |
+
5. **Editor-only styles** (`styles/editor/*.css`, 5 files)
|
| 73 |
+
- `_layout.css`: grid overrides (3-col symmetric, aligned with template), TOC drawer, responsive breakpoints (1100px collapse, 768px mobile)
|
| 74 |
+
- `_chrome.css`: ProseMirror editing visuals (placeholder, selection, cursors, comment marks, math editing)
|
| 75 |
+
- `_block-tools.css`: block handles (drag + add) and slash menu
|
| 76 |
+
- `_panels.css`: image upload card, footnote tooltip, citation panel
|
| 77 |
+
- `_hero-editable.css`: transparent click-to-edit inputs for FrontmatterHero
|
| 78 |
+
|
| 79 |
+
6. **Publisher CSS** (`_publisher.css`)
|
| 80 |
- Styles specific to the published static HTML page
|
| 81 |
+
- Theme toggle animations, wide/fullWidth breakout, sidenote float, lightbox, PDF link
|
| 82 |
+
- Only injected by the HTML renderer (backend), never loaded in the editor
|
| 83 |
|
| 84 |
### No CSS-in-JS
|
| 85 |
|
|
|
|
| 159 |
|
| 160 |
`GET /api/preview/:docName` renders the HTML without saving or uploading. Useful for testing the publisher pipeline.
|
| 161 |
|
| 162 |
+
## Auth and security
|
| 163 |
+
|
| 164 |
+
- AI chat routes (`/api/chat`, `/api/embed-chat`) are auth-guarded when OAuth is enabled
|
| 165 |
+
- The `requireEditor` middleware checks cookie token and verifies write access
|
| 166 |
+
- Published articles are served without auth (public)
|
| 167 |
+
|
| 168 |
## Testing
|
| 169 |
|
| 170 |
+
Tests use Vitest + Supertest. Run with `npm test` from `backend/`.
|
| 171 |
|
| 172 |
| Test file | What it covers |
|
| 173 |
|-----------|----------------|
|
|
|
|
| 178 |
| `tests/utils.test.ts` | Path sanitization utilities |
|
| 179 |
| `tests/auth.test.ts` | Token extraction, OAuth configuration |
|
| 180 |
| `tests/hf-storage.test.ts` | HF dataset storage configuration |
|
| 181 |
+
| `tests/persistence.test.ts` | Local file persistence, debounced save |
|
| 182 |
+
| `tests/api-routes.test.ts` | API route integration tests (publish, auth status) |
|
docs/SPECIFICATION.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
|
| 5 |
A collaborative, real-time scientific article editor deployed as a Hugging Face Space. Users write rich content (math, citations, custom components) in a TipTap-based editor synced via Yjs/Hocuspocus, then publish a self-contained static HTML article. An AI assistant helps with writing and editing.
|
| 6 |
|
| 7 |
-
**Stack**: React 18 +
|
| 8 |
|
| 9 |
**Relationship to `research-article-template`**: the CSS foundation, design tokens, and visual language come from the [research-article-template](https://huggingface.co/spaces/tfrere/research-article-template) project. The editor imports the template's CSS files (`_variables.css`, `_reset.css`, `_base.css`, `_layout.css`, component partials) and the publisher injects them inline into published HTML. The published output is designed to look identical to articles built with the Astro-based template.
|
| 10 |
|
|
@@ -152,7 +152,7 @@ flowchart LR
|
|
| 152 |
### 5.1 App Shell
|
| 153 |
|
| 154 |
- **No router** - single view with conditional rendering
|
| 155 |
-
- **Theme**:
|
| 156 |
- **Layout**: top bar (undo/redo, settings, publish, user chip) + 3-column CSS grid (TOC / editor / comments)
|
| 157 |
- **Chat**: floating button bottom-left, `ChatPanel` overlay
|
| 158 |
- **Modals**: comment dialog, settings drawer, publish confirmation
|
|
@@ -198,7 +198,7 @@ Registry-based system for MDX-like custom components:
|
|
| 198 |
| `rawHtml` | atomic | Raw HTML injection |
|
| 199 |
| `mermaid` | atomic | Mermaid diagram (live preview) |
|
| 200 |
|
| 201 |
-
- **Factory**: `
|
| 202 |
- **NodeViews**: `WrapperView` (editable content area + chrome), `AtomicView` (placeholder + field editor), `MermaidView` (textarea + SVG preview)
|
| 203 |
- **Slash menu integration**: each component generates a slash menu item via `getComponentSlashItems()`
|
| 204 |
|
|
@@ -214,7 +214,7 @@ Registry-based system for MDX-like custom components:
|
|
| 214 |
|
| 215 |
- **`TableOfContents`**: extracts headings from TipTap doc, scroll-based active state, collapsible sub-sections
|
| 216 |
- **`ChatPanel`**: message list + quick actions on selection + input with streaming
|
| 217 |
-
- **`
|
| 218 |
- **`BubbleToolbar`**: floating toolbar on text selection (bold, italic, link, comment, etc.)
|
| 219 |
- **`BlockHandle`**: drag handle for block-level nodes
|
| 220 |
|
|
@@ -222,25 +222,30 @@ Registry-based system for MDX-like custom components:
|
|
| 222 |
|
| 223 |
```
|
| 224 |
styles/
|
| 225 |
-
_variables.css #
|
| 226 |
-
_reset.css # Scoped reset
|
| 227 |
_base.css # Typography, scoped to article content
|
| 228 |
_layout.css # 3-column grid, .wide/.full-width helpers
|
| 229 |
_print.css # Print styles
|
| 230 |
-
|
| 231 |
-
|
|
|
|
| 232 |
toc.css # Editor TOC overrides
|
| 233 |
editing.css # Editor-only: layout, cursors, slash menu
|
|
|
|
| 234 |
components/
|
| 235 |
_code.css # Code blocks + syntax highlighting
|
| 236 |
_table.css # Tables
|
| 237 |
_tag.css # Tags
|
| 238 |
_card.css # Cards
|
| 239 |
_mermaid.css # Mermaid diagrams
|
|
|
|
|
|
|
| 240 |
_hero.css # Hero section (from template)
|
| 241 |
_toc.css # Base TOC styles (from template)
|
| 242 |
-
_button.css #
|
| 243 |
-
_form.css #
|
|
|
|
| 244 |
```
|
| 245 |
|
| 246 |
The publisher reads these same CSS files server-side and injects them inline into published HTML, using `resolveCustomMedia()` to expand `@custom-media` queries into standard `@media` rules.
|
|
@@ -389,7 +394,7 @@ sequenceDiagram
|
|
| 389 |
|
| 390 |
## 8. Current Limitations and Known Issues
|
| 391 |
|
| 392 |
-
- **
|
| 393 |
- **Single document**: only `"default"` document supported; no multi-doc
|
| 394 |
- **Single-user token**: last OAuth token cached globally for all HF API calls
|
| 395 |
- **No rate limiting** on `/api/chat` or `/api/citations/*`
|
|
|
|
| 4 |
|
| 5 |
A collaborative, real-time scientific article editor deployed as a Hugging Face Space. Users write rich content (math, citations, custom components) in a TipTap-based editor synced via Yjs/Hocuspocus, then publish a self-contained static HTML article. An AI assistant helps with writing and editing.
|
| 6 |
|
| 7 |
+
**Stack**: React 18 + TipTap 3 + Yjs (frontend) / Express + Hocuspocus + Node 20 (backend) / Docker on HF Spaces. No CSS-in-JS - all styling via vanilla CSS custom properties.
|
| 8 |
|
| 9 |
**Relationship to `research-article-template`**: the CSS foundation, design tokens, and visual language come from the [research-article-template](https://huggingface.co/spaces/tfrere/research-article-template) project. The editor imports the template's CSS files (`_variables.css`, `_reset.css`, `_base.css`, `_layout.css`, component partials) and the publisher injects them inline into published HTML. The published output is designed to look identical to articles built with the Astro-based template.
|
| 10 |
|
|
|
|
| 152 |
### 5.1 App Shell
|
| 153 |
|
| 154 |
- **No router** - single view with conditional rendering
|
| 155 |
+
- **Theme**: CSS custom properties with dynamic primary color from `settings.primaryHue` (OKLCH color model, synced via Yjs settings)
|
| 156 |
- **Layout**: top bar (undo/redo, settings, publish, user chip) + 3-column CSS grid (TOC / editor / comments)
|
| 157 |
- **Chat**: floating button bottom-left, `ChatPanel` overlay
|
| 158 |
- **Modals**: comment dialog, settings drawer, publish confirmation
|
|
|
|
| 198 |
| `rawHtml` | atomic | Raw HTML injection |
|
| 199 |
| `mermaid` | atomic | Mermaid diagram (live preview) |
|
| 200 |
|
| 201 |
+
- **Factory**: `createComponentExtension(def)` generates TipTap nodes from registry definitions (handles both wrapper and atomic kinds)
|
| 202 |
- **NodeViews**: `WrapperView` (editable content area + chrome), `AtomicView` (placeholder + field editor), `MermaidView` (textarea + SVG preview)
|
| 203 |
- **Slash menu integration**: each component generates a slash menu item via `getComponentSlashItems()`
|
| 204 |
|
|
|
|
| 214 |
|
| 215 |
- **`TableOfContents`**: extracts headings from TipTap doc, scroll-based active state, collapsible sub-sections
|
| 216 |
- **`ChatPanel`**: message list + quick actions on selection + input with streaming
|
| 217 |
+
- **`CommentPopover`**: positioned comment popover anchored to the active thread (resolve/delete inline)
|
| 218 |
- **`BubbleToolbar`**: floating toolbar on text selection (bold, italic, link, comment, etc.)
|
| 219 |
- **`BlockHandle`**: drag handle for block-level nodes
|
| 220 |
|
|
|
|
| 222 |
|
| 223 |
```
|
| 224 |
styles/
|
| 225 |
+
_variables.css # Template tokens: --primary-color, breakpoints, @custom-media
|
| 226 |
+
_reset.css # Scoped reset for article content
|
| 227 |
_base.css # Typography, scoped to article content
|
| 228 |
_layout.css # 3-column grid, .wide/.full-width helpers
|
| 229 |
_print.css # Print styles
|
| 230 |
+
_ui.css # Editor chrome: buttons, dialogs, drawers, spinner
|
| 231 |
+
tokens.css # Design tokens (light/dark): text, bg, accent, code, danger, shadows
|
| 232 |
+
article.css # .tiptap content styles (shared editor/published)
|
| 233 |
toc.css # Editor TOC overrides
|
| 234 |
editing.css # Editor-only: layout, cursors, slash menu
|
| 235 |
+
_publisher.css # Published-only: theme toggle, wide/fullWidth, footer, lightbox
|
| 236 |
components/
|
| 237 |
_code.css # Code blocks + syntax highlighting
|
| 238 |
_table.css # Tables
|
| 239 |
_tag.css # Tags
|
| 240 |
_card.css # Cards
|
| 241 |
_mermaid.css # Mermaid diagrams
|
| 242 |
+
_embed.css # Embed containers
|
| 243 |
+
_embed-studio.css # Embed studio overlay
|
| 244 |
_hero.css # Hero section (from template)
|
| 245 |
_toc.css # Base TOC styles (from template)
|
| 246 |
+
_button.css # Buttons (template)
|
| 247 |
+
_form.css # Form elements (template)
|
| 248 |
+
_footer.css # Footer (template)
|
| 249 |
```
|
| 250 |
|
| 251 |
The publisher reads these same CSS files server-side and injects them inline into published HTML, using `resolveCustomMedia()` to expand `@custom-media` queries into standard `@media` rules.
|
|
|
|
| 394 |
|
| 395 |
## 8. Current Limitations and Known Issues
|
| 396 |
|
| 397 |
+
- **Test suite in progress**: P0 tests being added (see `docs/TESTS.md`)
|
| 398 |
- **Single document**: only `"default"` document supported; no multi-doc
|
| 399 |
- **Single-user token**: last OAuth token cached globally for all HF API calls
|
| 400 |
- **No rate limiting** on `/api/chat` or `/api/citations/*`
|