overleaf-review 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -50
- package/dist/cli.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,78 +1,105 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="assets/logo.svg" alt="overleaf-review" width="120" height="120" />
|
|
4
|
+
|
|
1
5
|
# overleaf-review
|
|
2
6
|
|
|
3
7
|
**The missing review layer for Overleaf's Git bridge.**
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
Sync **comments** *and* **tracked changes** between Overleaf and your local repo — both directions.
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/overleaf-review)
|
|
12
|
+
[](https://www.npmjs.com/package/overleaf-review)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
[](package.json)
|
|
15
|
+
|
|
16
|
+
`Overleaf` ⇄ **overleaf-review** ⇄ `your git repo + editor + AI tools`
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
</div>
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
and `.json`) so your tools have every co-author note in context.
|
|
15
|
-
- **`push`** — turn your local edits into tracked-change suggestions in Overleaf, mapping files
|
|
16
|
-
to Overleaf docs by path (push one with `--file`, or every changed `.tex` at once). `--dry-run`
|
|
17
|
-
previews the exact ops first.
|
|
18
|
-
- **`comment` / `resolve`** — create a comment anchored on any text, and resolve/reopen threads.
|
|
20
|
+
---
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
> talks to the same real-time and thread endpoints the web editor uses. It is **not affiliated
|
|
22
|
-
> with or endorsed by Overleaf**, may break when Overleaf changes internals, and should be used
|
|
23
|
-
> on your own account and projects. MIT licensed — use at your own risk.
|
|
22
|
+
## The problem
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
Overleaf's Git integration syncs your `.tex` source — but silently **drops the entire
|
|
25
|
+
collaborative review layer**. Co-authors' comments (with their text anchors) and tracked changes
|
|
26
|
+
live in Overleaf's own database and never reach your repo. So if you draft locally (say, in VS Code
|
|
27
|
+
with an AI assistant) and sync via Git, you can't see the feedback your co-authors leave in
|
|
28
|
+
Overleaf, and you can't push suggestions back.
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
**`push`** (with `--dry-run`), **`comment`**, and **`resolve`** — comments *and* tracked changes,
|
|
30
|
-
both directions. Next: multi-file mapping and `npm publish`.
|
|
30
|
+
`overleaf-review` bridges that gap — a direct Overleaf client that runs *alongside* your Git
|
|
31
|
+
workflow and carries the review layer Git can't represent.
|
|
31
32
|
|
|
32
|
-
##
|
|
33
|
+
## ✨ Features
|
|
34
|
+
|
|
35
|
+
- 📥 **`pull`** — read comments + tracked changes (with anchors) into a Git-friendly sidecar
|
|
36
|
+
(`.overleaf/reviews.md` + `.json`), so your tools have every co-author note in context.
|
|
37
|
+
- 📤 **`push`** — turn local edits into **tracked-change suggestions**, mapping files to Overleaf
|
|
38
|
+
docs by path (one file, or every changed `.tex` at once). `--dry-run` previews the exact ops.
|
|
39
|
+
- 💬 **`comment` / `resolve`** — anchor a comment on any text, and resolve/reopen threads.
|
|
40
|
+
- 🔑 **`login`** — validated auth stored outside your repo (chmod 600); `--browser` mode is
|
|
41
|
+
institutional-SSO friendly.
|
|
42
|
+
|
|
43
|
+
## 📦 Install
|
|
33
44
|
|
|
34
45
|
```bash
|
|
35
46
|
npm install -g overleaf-review
|
|
36
47
|
```
|
|
37
48
|
|
|
38
|
-
|
|
39
|
-
`npx tsx src/cli.ts <command>` (as shown below).
|
|
40
|
-
|
|
41
|
-
## Getting started
|
|
49
|
+
## 🚀 Quick start
|
|
42
50
|
|
|
43
51
|
```bash
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
npx tsx src/cli.ts login # paste your overleaf_session2 cookie, or:
|
|
48
|
-
npx tsx src/cli.ts login --browser # opens your Chrome, log in normally (SSO works)
|
|
52
|
+
# 1. Authenticate (stored in ~/.config/overleaf-review/, never in the repo)
|
|
53
|
+
overleaf-review login # paste your overleaf_session2 cookie, or:
|
|
54
|
+
overleaf-review login --browser # opens your Chrome, log in normally (SSO works)
|
|
49
55
|
|
|
50
56
|
# 2. Link this repo to an Overleaf project (id from the project URL)
|
|
51
|
-
|
|
57
|
+
overleaf-review link --project 6a4c…bec5a
|
|
52
58
|
|
|
53
59
|
# 3. Sync the review layer
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
npx tsx src/cli.ts resolve --thread <id> # thread ids come from `pull`
|
|
60
|
+
overleaf-review pull # comments + changes → .overleaf/
|
|
61
|
+
overleaf-review push --dry-run # preview local edits as suggestions
|
|
62
|
+
overleaf-review push # send them as tracked changes
|
|
63
|
+
overleaf-review comment --anchor "Introduction" --message "Expand this section"
|
|
64
|
+
overleaf-review resolve --thread <id> # thread ids come from `pull`
|
|
60
65
|
```
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
`~/.config/overleaf-review/credentials.json` (chmod 600), never in the repo. `--browser` needs
|
|
64
|
-
Playwright (`npm i -D playwright`) and drives your installed Chrome — no extra download — and
|
|
65
|
-
works with institutional SSO. For dev you can instead put `OVERLEAF_SESSION2` and
|
|
66
|
-
`OVERLEAF_PROJECT_ID` in a gitignored `.env` (env vars take priority).
|
|
67
|
+
## 🧭 Commands
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
| Command | What it does |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `login [--cookie <v>] [--browser]` | Authenticate and store your session (SSO-friendly `--browser`) |
|
|
72
|
+
| `link --project <id>` | Link this repo to an Overleaf project (`.overleaf/config.json`) |
|
|
73
|
+
| `pull [--out <dir>]` | Read comments + tracked changes into a sidecar |
|
|
74
|
+
| `push [--file <f>] [--doc <name>] [--dry-run]` | Send local edits as tracked-change suggestions (all changed `.tex` if no `--file`) |
|
|
75
|
+
| `comment --anchor <text> --message <text> [--doc <name>] [--nth <n>]` | Add a comment anchored on the given text |
|
|
76
|
+
| `resolve --thread <id> [--reopen]` | Resolve (or reopen) a comment thread |
|
|
77
|
+
|
|
78
|
+
## 🧠 How it works
|
|
69
79
|
|
|
70
80
|
overleaf.com's editor speaks an old **socket.io 0.9** protocol over a WebSocket. The client
|
|
71
|
-
([`src/overleaf-socket.ts`](src/overleaf-socket.ts)) joins the project
|
|
72
|
-
`ranges` (comments + tracked changes)
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
([`src/overleaf-socket.ts`](src/overleaf-socket.ts)) joins the project and reads each doc's
|
|
82
|
+
`ranges` (comments + tracked changes). To write, it sends `applyOtUpdate` ops:
|
|
83
|
+
|
|
84
|
+
- a **tracked change** is an insert/delete op with a `meta.tc` flag;
|
|
85
|
+
- a **comment** is a `c` op plus a REST post of the message text.
|
|
86
|
+
|
|
87
|
+
`push` diffs your local file against Overleaf's current content and translates the hunks into
|
|
88
|
+
sequential OT ops, so your edits land as reviewable suggestions rather than silent changes.
|
|
89
|
+
|
|
90
|
+
## ⚠️ Disclaimer
|
|
91
|
+
|
|
92
|
+
**Unofficial.** Overleaf has no public API for comments or tracked changes, so this tool talks to
|
|
93
|
+
the same internal real-time and thread endpoints the web editor uses. It is **not affiliated with
|
|
94
|
+
or endorsed by Overleaf**, may break when Overleaf changes internals, and should be used on your
|
|
95
|
+
own account and projects. Use at your own risk.
|
|
96
|
+
|
|
97
|
+
## 🗺️ Roadmap
|
|
98
|
+
|
|
99
|
+
- Reply-to-thread and delete-comment
|
|
100
|
+
- A `pull` that also writes doc content (not just the review sidecar)
|
|
101
|
+
- Trusted-publishing CI
|
|
75
102
|
|
|
76
|
-
## License
|
|
103
|
+
## 📄 License
|
|
77
104
|
|
|
78
|
-
MIT © Miguel Castellano
|
|
105
|
+
MIT © [Miguel Castellano](https://github.com/michu5696)
|
package/dist/cli.js
CHANGED
|
@@ -455,11 +455,11 @@ function renderMarkdown(d) {
|
|
|
455
455
|
import { readFileSync as readFileSync3, readdirSync } from "fs";
|
|
456
456
|
import { relative, resolve as resolvePath, sep } from "path";
|
|
457
457
|
import { randomBytes } from "crypto";
|
|
458
|
-
import {
|
|
458
|
+
import { diffWordsWithSpace } from "diff";
|
|
459
459
|
function buildOps(remote, local) {
|
|
460
460
|
const ops = [];
|
|
461
461
|
let p = 0;
|
|
462
|
-
for (const part of
|
|
462
|
+
for (const part of diffWordsWithSpace(remote, local)) {
|
|
463
463
|
if (part.added) {
|
|
464
464
|
ops.push({ p, i: part.value });
|
|
465
465
|
p += part.value.length;
|
package/package.json
CHANGED