overleaf-review 0.3.0 → 0.4.0

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.
Files changed (3) hide show
  1. package/README.md +94 -15
  2. package/dist/cli.js +3204 -371
  3. package/package.json +4 -2
package/README.md CHANGED
@@ -35,14 +35,24 @@ workflow and carries the review layer Git can't represent.
35
35
  - 📥 **`pull`** — read comments + tracked changes (with anchors) into a Git-friendly sidecar
36
36
  (`.overleaf/reviews.md` + `.json`), so your tools have every co-author note in context.
37
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
- `--direct` sends plain edits instead of suggestions.
38
+ docs by path (one file, or every changed `.tex` at once). A saved Base/Local/Live merge keeps
39
+ non-overlapping co-author edits, while overlapping edits and active tracked-change ranges stop
40
+ the push for inspection. `--direct` sends plain edits instead of suggestions.
40
41
  - 🔄 **`fetch`** — write Overleaf's current text back down into your repo (read-only on Overleaf, so
41
- it cannot disturb a single comment or tracked change).
42
+ it cannot disturb a single comment or tracked change) and save the synchronization base used by
43
+ future pushes. Existing local files are snapshotted before replacement.
44
+ - 📋 **`review plan` / `review submit`** — save a complete, binding push plan, inspect it, then
45
+ submit it only if the local file, saved base, live document version, and review ranges are still
46
+ unchanged.
42
47
  - 🖼️ **`upload`** — push figures, PDFs, or new files into Overleaf.
43
48
  - 💬 **`comment` / `reply` / `resolve` / `delete-comment` / `delete-message`** — full comment
44
49
  control: start a thread, reply, resolve/reopen, delete a whole thread or a single message.
45
- - **`accept` / `reject`** act on your collaborators' tracked changes from the CLI.
50
+ Identical recent comments and replies are retry-safe by default; `--force` deliberately posts
51
+ another copy.
52
+ - ✅ **`accept` / `reject`** — act on collaborators' tracked changes and verify removal of every
53
+ requested change id before reporting success; rejection also verifies the exact resulting text.
54
+ - 🧾 **Review receipts** — pushes, accept/reject actions, comments, and replies leave durable JSON
55
+ records under `.overleaf/receipts/` showing what was verified or left ambiguous.
46
56
  - 🔑 **`login`** — validated auth stored outside your repo (chmod 600); `--browser` mode is
47
57
  institutional-SSO friendly.
48
58
 
@@ -60,9 +70,11 @@ ops that Overleaf *transforms the review ranges against*, so comments and tracke
60
70
 
61
71
  | Need | Command |
62
72
  | --- | --- |
63
- | Overleaf text your repo | `fetch` |
73
+ | Begin a local review session | `review start` |
74
+ | Overleaf text → your repo and save Base | `fetch` |
64
75
  | Your edits → Overleaf, as suggestions | `push` |
65
76
  | Your edits → Overleaf, directly | `push --direct` |
77
+ | Inspect, then submit the exact same change | `review plan --out plan.json`, then `review submit --plan plan.json` |
66
78
  | Figures / new files → Overleaf | `upload` |
67
79
 
68
80
  Your Git repo stays a completely normal repo — commit whatever you like, `.tex` included — and
@@ -85,14 +97,28 @@ overleaf-review login --browser # opens your Chrome, log in normally (SSO work
85
97
  # 2. Link this repo to an Overleaf project (id from the project URL)
86
98
  overleaf-review link --project 6a4c…bec5a
87
99
 
88
- # 3. Sync the review layer
89
- overleaf-review pull # comments + changes .overleaf/
90
- overleaf-review push --dry-run # preview local edits as suggestions
91
- overleaf-review push # send them as tracked changes
100
+ # 3. Start from Overleaf's current text and review state
101
+ overleaf-review review start # fetch text + save Base + pull reviews
102
+
103
+ # 4. Edit locally, then inspect and submit a binding plan
104
+ overleaf-review review plan --out .overleaf/push-plan.json
105
+ overleaf-review review submit --plan .overleaf/push-plan.json
106
+
107
+ # Or use the safe one-shot form when a separate approval step is unnecessary
108
+ overleaf-review push --dry-run # transient preview; sends nothing
109
+ overleaf-review push # plan, validate, send, and verify
110
+
111
+ # 5. Work with review threads
92
112
  overleaf-review comment --anchor "Introduction" --message "Expand this section"
93
113
  overleaf-review resolve --thread <id> # thread ids come from `pull`
94
114
  ```
95
115
 
116
+ `fetch` and `review start` write Overleaf's text into the local files, so commit or otherwise
117
+ preserve local-only work before running them. They save `.overleaf/base.json`; edit only after that
118
+ base is established. Existing installations should run one of these commands once before their
119
+ first safe push. If an upgraded repository already has unpushed edits, copy or stash them, run
120
+ `fetch`, then restore the edits so the new Base remains the Overleaf version they were based on.
121
+
96
122
  ## 🧭 Commands
97
123
 
98
124
  | Command | What it does |
@@ -100,11 +126,14 @@ overleaf-review resolve --thread <id> # thread ids come from `pull`
100
126
  | `login [--cookie <v>] [--browser]` | Authenticate and store your session (SSO-friendly `--browser`) |
101
127
  | `link --project <id>` | Link this repo to an Overleaf project (`.overleaf/config.json`) |
102
128
  | `pull [--out <dir>]` | Read comments + tracked changes into a sidecar |
103
- | `fetch [--file <f>] [--dry-run]` | Write Overleaf's text down into local files (read-only on Overleaf) |
129
+ | `fetch [--file <f>] [--dry-run]` | Write Overleaf text locally, snapshot replaced files, and save Base (read-only on Overleaf) |
130
+ | `review start [--file <f>] [--out <dir>]` | Fetch text, save the synchronization base, and pull the review sidecar |
131
+ | `review plan --out <plan.json> [--file <f>] [--doc <name>] [--direct] [--allow-overlap] [--unsafe-no-base]` | Create a complete binding plan without changing Overleaf |
132
+ | `review submit --plan <plan.json> [--acknowledge-ambiguous]` | Submit that plan only if all recorded preconditions still match |
104
133
  | `upload <path…> [--folder <name>]` | Upload figures / new files into Overleaf |
105
- | `push [--file <f>] [--doc <name>] [--direct] [--dry-run]` | Send local edits as tracked suggestions (all changed `.tex` if no `--file`); `--direct` for plain edits |
106
- | `comment --anchor <text> --message <text> [--doc <name>] [--nth <n>]` | Add a comment anchored on the given text |
107
- | `reply --thread <id> --message <text>` | Reply to an existing comment thread |
134
+ | `push [--file <f>] [--doc <name>] [--direct] [--dry-run] [--plan-out <path>] [--plan <path>] [--allow-overlap] [--unsafe-no-base] [--acknowledge-ambiguous]` | Safely merge and send local edits (all changed `.tex` if no `--file`) |
135
+ | `comment --anchor <text> --message <text> [--doc <name>] [--nth <n>] [--force]` | Add an anchored comment; recent identical retries are skipped unless forced |
136
+ | `reply --thread <id> --message <text> [--force]` | Reply to a thread; recent identical retries are skipped unless forced |
108
137
  | `resolve --thread <id> [--reopen]` | Resolve (or reopen) a comment thread |
109
138
  | `delete-comment --thread <id>` | Delete a whole comment thread |
110
139
  | `delete-message --message-id <id> [--thread <id>]` | Delete a single message within a thread |
@@ -113,6 +142,52 @@ overleaf-review resolve --thread <id> # thread ids come from `pull`
113
142
 
114
143
  Thread and change ids are listed by `pull` (in `.overleaf/reviews.md`).
115
144
 
145
+ ### Safe pushes
146
+
147
+ A normal push compares three versions of each document:
148
+
149
+ - **Base** — the Overleaf text saved by the last `fetch` or successful push;
150
+ - **Local** — your current file;
151
+ - **Live** — the document as it exists in Overleaf when planning.
152
+
153
+ Your Base→Local intent is rebased onto Live. Non-overlapping live edits are preserved; genuinely
154
+ overlapping Base→Local and Base→Live edits abort instead of silently undoing a collaborator's
155
+ work. A proposed edit that intersects an active tracked-change range is also blocked by default and
156
+ the relevant change ids are listed.
157
+
158
+ Use `--allow-overlap` only after inspecting those tracked changes. `--unsafe-no-base` is a deliberate
159
+ legacy escape hatch that treats the current Live document as Base; it loses the protection against
160
+ co-author edits made since your local file was obtained. `--direct` changes how the validated ops
161
+ are represented in Overleaf, not the merge and conflict checks.
162
+
163
+ For a separate approval step, `review plan --out plan.json` stores the full operation list and its
164
+ preconditions, active tracked ranges, and any comment overlaps. `review submit --plan plan.json`
165
+ re-derives the plan from Base/Local/Live and aborts if preflight finds that the project, local source,
166
+ synchronization base, live document version/content, or active review ranges changed. Plans contain
167
+ manuscript fragments, so store or commit them with the same care as the source itself. `push
168
+ --plan-out <path>` and `push --plan <path>` expose the same workflow through the one-level command.
169
+
170
+ Overleaf can transform an update that races with a collaborator after the final preflight. The tool
171
+ therefore reads every result back and fails rather than claiming success when the exact planned text
172
+ is not present. A multi-file submission is not transactional; if a later file fails, its receipt
173
+ identifies every earlier file already verified on Overleaf.
174
+
175
+ Pushes, accept/reject actions, comments, and replies write audit receipts beneath
176
+ `.overleaf/receipts/`. Keep an ambiguous receipt: it means the request may have reached Overleaf but
177
+ readback could not prove the result, so inspect the live project before retrying. For comments and
178
+ replies, an identical recent message is treated as a retry and skipped; pass `--force` only when a
179
+ second identical message is intentional.
180
+
181
+ An ambiguous push quarantines its affected documents even if a newly generated plan has a different
182
+ timestamp or tracked-change seed. After waiting for delayed updates and manually reconciling the
183
+ receipt against live Overleaf, `--acknowledge-ambiguous` explicitly clears that submission-time
184
+ guard; it should never be used as an automatic retry flag.
185
+
186
+ Mutating commands are serialized by a working-tree-specific lock in the system temporary directory,
187
+ preventing two local agents from racing through the same preflight. A normal exit removes the lock.
188
+ If a process crashes and leaves it behind, the next command prints its exact path; inspect any
189
+ relevant receipt and the live Overleaf document before removing it manually.
190
+
116
191
  ## 🧠 How it works
117
192
 
118
193
  overleaf.com's editor speaks an old **socket.io 0.9** protocol over a WebSocket. The client
@@ -122,8 +197,12 @@ overleaf.com's editor speaks an old **socket.io 0.9** protocol over a WebSocket.
122
197
  - a **tracked change** is an insert/delete op with a `meta.tc` flag;
123
198
  - a **comment** is a `c` op plus a REST post of the message text.
124
199
 
125
- `push` diffs your local file against Overleaf's current content and translates the hunks into
126
- sequential OT ops, so your edits land as reviewable suggestions rather than silent changes.
200
+ `push` performs the Base/Local/Live merge described above, translates Live→merged text into
201
+ sequential OT ops, and waits for Overleaf's applied-update event. It then reads the document back
202
+ and verifies the final text—and, in suggestion mode, tracked-change ids—before updating the saved
203
+ base. Accept and reject operations verify that the requested ids disappeared; rejection also
204
+ verifies the exact planned text. Push, accept/reject, comment, and reply fail loudly when their
205
+ readback cannot prove success.
127
206
 
128
207
  ## ⚠️ Disclaimer
129
208