overleaf-review 0.2.0 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +4 -3
  2. package/dist/cli.js +37 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -36,8 +36,8 @@ workflow and carries the review layer Git can't represent.
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
38
  docs by path (one file, or every changed `.tex` at once). `--dry-run` previews the exact ops.
39
- - 💬 **`comment` / `reply` / `resolve` / `delete-comment`** — full comment-thread control:
40
- start a thread, reply, resolve/reopen, or delete.
39
+ - 💬 **`comment` / `reply` / `resolve` / `delete-comment` / `delete-message`** — full comment
40
+ control: start a thread, reply, resolve/reopen, delete a whole thread or a single message.
41
41
  - ✅ **`accept` / `reject`** — act on your collaborators' tracked changes from the CLI.
42
42
  - 🔑 **`login`** — validated auth stored outside your repo (chmod 600); `--browser` mode is
43
43
  institutional-SSO friendly.
@@ -77,7 +77,8 @@ overleaf-review resolve --thread <id> # thread ids come from `pull`
77
77
  | `comment --anchor <text> --message <text> [--doc <name>] [--nth <n>]` | Add a comment anchored on the given text |
78
78
  | `reply --thread <id> --message <text>` | Reply to an existing comment thread |
79
79
  | `resolve --thread <id> [--reopen]` | Resolve (or reopen) a comment thread |
80
- | `delete-comment --thread <id>` | Delete a comment thread |
80
+ | `delete-comment --thread <id>` | Delete a whole comment thread |
81
+ | `delete-message --message-id <id> [--thread <id>]` | Delete a single message within a thread |
81
82
  | `accept --change <id> …` | Accept collaborators' tracked change(s) |
82
83
  | `reject --change <id> …` | Reject collaborators' tracked change(s) |
83
84
 
package/dist/cli.js CHANGED
@@ -327,6 +327,14 @@ async function acceptChanges(docId, changeIds, csrf) {
327
327
  if (!res.ok) throw new Error(`acceptChanges ${res.status}: ${(await res.text()).slice(0, 200)}`);
328
328
  return res.status;
329
329
  }
330
+ async function deleteMessage(threadId, messageId, csrf) {
331
+ const res = await fetch(
332
+ `${config.baseUrl}/project/${config.projectId}/thread/${threadId}/messages/${messageId}`,
333
+ { method: "DELETE", headers: headers({ "X-CSRF-Token": csrf }) }
334
+ );
335
+ if (!res.ok) throw new Error(`deleteMessage ${res.status}: ${(await res.text()).slice(0, 200)}`);
336
+ return res.status;
337
+ }
330
338
  async function deleteThread(docId, threadId, csrf) {
331
339
  const res = await fetch(
332
340
  `${config.baseUrl}/project/${config.projectId}/doc/${docId}/thread/${threadId}`,
@@ -399,6 +407,7 @@ async function pull(outDir = ".overleaf") {
399
407
  context: lineContext(state.lines, line),
400
408
  resolved: Boolean(thread.resolved),
401
409
  messages: (thread.messages ?? []).map((m) => ({
410
+ id: m.id,
402
411
  author: m.user?.first_name ?? members[m.user_id] ?? m.user_id,
403
412
  email: m.user?.email,
404
413
  content: m.content,
@@ -440,7 +449,7 @@ function renderMarkdown(d) {
440
449
  L.push(`_Pulled ${d.pulledAt} from project \`${d.projectId}\`._`, "");
441
450
  L.push(`**${d.comments.length}** comment(s), **${d.changes.length}** tracked change(s).`, "");
442
451
  L.push(
443
- "_Act on these:_ `reply --thread <id> --message <text>` \xB7 `resolve --thread <id>` \xB7 `delete-comment --thread <id>` \xB7 `accept --change <id>` \xB7 `reject --change <id>`.",
452
+ "_Act on these:_ `reply --thread <id> --message <text>` \xB7 `resolve --thread <id>` \xB7 `delete-comment --thread <id>` \xB7 `delete-message --message-id <id>` \xB7 `accept --change <id>` \xB7 `reject --change <id>`.",
444
453
  ""
445
454
  );
446
455
  const byDoc = (items) => {
@@ -458,7 +467,7 @@ function renderMarkdown(d) {
458
467
  L.push(`\`thread ${c.threadId}\``);
459
468
  L.push("```", c.context, "```");
460
469
  for (const m of c.messages) {
461
- L.push(`- **${m.author}**: ${m.content}`);
470
+ L.push(`- **${m.author}**: ${m.content} \`msg ${m.id}\``);
462
471
  }
463
472
  if (!c.messages.length) L.push("- _(no message text)_");
464
473
  L.push("");
@@ -678,6 +687,24 @@ async function deleteComment(threadId) {
678
687
  console.log(`\u2705 Deleted comment thread ${threadId}`);
679
688
  }
680
689
 
690
+ // src/commands/delete-message.ts
691
+ async function deleteThreadMessage(messageId, threadId) {
692
+ const csrf = await getCsrfToken();
693
+ let tid = threadId;
694
+ if (!tid) {
695
+ const threads = await getThreads();
696
+ for (const [t, v] of Object.entries(threads)) {
697
+ if (v.messages?.some((m) => m.id === messageId)) {
698
+ tid = t;
699
+ break;
700
+ }
701
+ }
702
+ }
703
+ if (!tid) throw new Error(`message ${messageId} not found in any thread`);
704
+ await deleteMessage(tid, messageId, csrf);
705
+ console.log(`\u2705 Deleted message ${messageId} from thread ${tid}`);
706
+ }
707
+
681
708
  // src/commands/accept.ts
682
709
  async function accept(changeIds) {
683
710
  const { socket, docs } = await openProject();
@@ -808,7 +835,8 @@ function usage() {
808
835
  console.log(" comment --anchor <text> --message <text> [--doc <name>] [--nth <n>]");
809
836
  console.log(" reply --thread <id> --message <text> Reply to an existing thread");
810
837
  console.log(" resolve --thread <id> [--reopen] Resolve/reopen a thread");
811
- console.log(" delete-comment --thread <id> Delete a thread\n");
838
+ console.log(" delete-comment --thread <id> Delete a whole thread");
839
+ console.log(" delete-message --message-id <id> Delete a single message\n");
812
840
  console.log("Tracked changes:");
813
841
  console.log(" push [--file <f>] [--doc <name>] [--dry-run] Send local edits as suggestions");
814
842
  console.log(" accept --change <id> [--change <id> \u2026] Accept collaborators\u2019 changes");
@@ -869,6 +897,12 @@ async function main() {
869
897
  await deleteComment(thread);
870
898
  break;
871
899
  }
900
+ case "delete-message": {
901
+ const messageId = getFlag("message-id");
902
+ if (!messageId) fail("delete-message requires --message-id <id>");
903
+ await deleteThreadMessage(messageId, getFlag("thread"));
904
+ break;
905
+ }
872
906
  case "accept": {
873
907
  const ids = getAll("change");
874
908
  if (!ids.length) fail("accept requires --change <id>");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overleaf-review",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "The missing review layer for Overleaf's Git bridge — sync comments and tracked changes between Overleaf and your local repo.",
5
5
  "type": "module",
6
6
  "license": "MIT",