@aloth/olcli 0.15.2 → 0.16.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.
- package/README.md +140 -437
- package/dist/browser-auth.d.ts +144 -0
- package/dist/browser-auth.d.ts.map +1 -0
- package/dist/browser-auth.js +442 -0
- package/dist/browser-auth.js.map +1 -0
- package/dist/cli.js +455 -177
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +52 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +199 -42
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +40 -7
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +115 -0
- package/dist/errors.js.map +1 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +27 -19
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +1 -1
- package/dist/move-plan.d.ts +75 -0
- package/dist/move-plan.d.ts.map +1 -0
- package/dist/move-plan.js +168 -0
- package/dist/move-plan.js.map +1 -0
- package/dist/paths.d.ts +18 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +45 -0
- package/dist/paths.js.map +1 -1
- package/dist/project-match.d.ts +37 -0
- package/dist/project-match.d.ts.map +1 -0
- package/dist/project-match.js +97 -0
- package/dist/project-match.js.map +1 -0
- package/dist/proxy.d.ts +52 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +189 -0
- package/dist/proxy.js.map +1 -0
- package/dist/remote-helper.js +3 -2
- package/dist/remote-helper.js.map +1 -1
- package/dist/term.d.ts +25 -0
- package/dist/term.d.ts.map +1 -0
- package/dist/term.js +42 -0
- package/dist/term.js.map +1 -0
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -1,530 +1,233 @@
|
|
|
1
|
-
# olcli
|
|
1
|
+
# olcli: Overleaf CLI
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Work on Overleaf projects from your terminal while your coauthors keep using the Overleaf web editor.** Pull, push, sync, diff and compile LaTeX projects; read and answer review comments; use Overleaf as a git remote; give AI agents an MCP server that asks you before it writes.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/aloth/olcli/actions/workflows/ci.yml)
|
|
6
6
|
[](https://www.npmjs.com/package/@aloth/olcli)
|
|
7
7
|
[](https://www.npmjs.com/package/@aloth/olcli)
|
|
8
|
-
[](https://github.com/aloth/olcli)
|
|
9
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
[](https://doi.org/10.5281/zenodo.23896243)
|
|
11
|
+
[](https://glama.ai/mcp/servers/aloth/olcli)
|
|
10
12
|
[](https://agentskills.io)
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
- **Coauthors change nothing.** They keep editing, commenting and compiling in the browser; you work in Vim, VS Code, Emacs or an agent and sync with the same project.
|
|
15
|
+
- **Works on the free Overleaf plan.** Pull, push, sync, diff, latexdiff, compile, PDF and output downloads, file operations, zip, comment listing and the git remote helper were checked on a free overleaf.com account. Tracked changes are the exception: Overleaf itself only offers them in premium projects.
|
|
16
|
+
- **Works on self-hosted Overleaf Community Edition** with the same commands.
|
|
17
|
+
- **No git token, no paid plan.** olcli signs in with your normal Overleaf session. Overleaf's own Git integration is a premium feature; olcli's git remote helper is not tied to it.
|
|
18
|
+
- **One package:** command-line tool, git remote helper, MCP server and TypeScript library.
|
|
13
19
|
|
|
14
20
|
<p align="center">
|
|
15
21
|
<img src="screenshots/demo.gif" alt="olcli demo" width="600">
|
|
16
22
|
</p>
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
<p align="center">
|
|
25
|
+
<img src="screenshots/latexdiff.gif" alt="olcli diff --latexdiff --pdf turns a local edit into a marked-up PDF" width="600">
|
|
26
|
+
</p>
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
- ✨ **Create** blank or example projects
|
|
22
|
-
- ⬇️ **Pull** project files to local directory for offline editing
|
|
23
|
-
- ⬆️ **Push** local changes back to Overleaf
|
|
24
|
-
- 🔄 **Sync** bidirectionally with smart conflict detection
|
|
25
|
-
- 🔍 **Diff** local files against the live remote before pushing
|
|
26
|
-
- 📝 **Marked-up revisions** — `diff --latexdiff` produces the struck-through/underlined PDF advisors and journals ask for
|
|
27
|
-
- 🔀 **Git remote** — use Overleaf as a native git remote ([docs](docs/GIT-REMOTE.md))
|
|
28
|
-
- ✌️ **Two-way deletions** — files removed locally are deleted on Overleaf on next sync
|
|
29
|
-
- 🗑️ **Delete** and ✏️ **rename** remote files by path
|
|
30
|
-
- 🚫 **Smart ignore** — LaTeX build artifacts and OS noise filtered automatically; extend with `.olignore`
|
|
31
|
-
- 📄 **Compile** PDFs using Overleaf's remote compiler
|
|
32
|
-
- 📦 **Download** individual files or full project archives
|
|
33
|
-
- 📤 **Upload** files to projects
|
|
34
|
-
- 💬 **Review comments** — list, add, resolve, reopen, delete, and reply to threads
|
|
35
|
-
- 🗂️ **Preserve folder structure** when pushing nested files
|
|
36
|
-
- ⏱️ **Configurable timeout** for slow connections
|
|
37
|
-
- 🔑 **Password login** for self-hosted instances (no browser required)
|
|
38
|
-
- ⚙️ **Self-hosted Overleaf/ShareLaTeX** support
|
|
39
|
-
- 📊 **Output** compile artifacts (`.bbl`, `.log`, `.aux` for arXiv submissions)
|
|
40
|
-
- 🤖 **MCP server** for AI assistants ([docs](docs/MCP.md))
|
|
41
|
-
|
|
42
|
-
**Perfect for:**
|
|
43
|
-
- Editing LaTeX in your preferred text editor (Vim, VS Code, Emacs, etc.)
|
|
44
|
-
- Version control with Git while using Overleaf's compiler
|
|
45
|
-
- Automating workflows and CI/CD pipelines
|
|
46
|
-
- Offline work with periodic sync
|
|
47
|
-
|
|
48
|
-
## Installation
|
|
49
|
-
|
|
50
|
-
### Homebrew (macOS/Linux)
|
|
28
|
+
## Install
|
|
51
29
|
|
|
52
30
|
```bash
|
|
53
|
-
brew
|
|
54
|
-
|
|
31
|
+
brew install aloth/tap/olcli # Homebrew (macOS, Linux)
|
|
32
|
+
npm install -g @aloth/olcli # npm (any platform, Node 20.18.1 or newer)
|
|
55
33
|
```
|
|
56
34
|
|
|
57
|
-
|
|
35
|
+
On Linux with Nix: `nix run github:aloth/olcli -- --help`. Without installing: `npx @aloth/olcli list`. For AI agents through AgentSkills: `npx skills add aloth/olcli`.
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
58
38
|
|
|
59
39
|
```bash
|
|
60
|
-
|
|
40
|
+
olcli auth --browser # sign in through a browser window
|
|
41
|
+
olcli list # your projects
|
|
42
|
+
olcli pull "My Thesis" # download into ./My_Thesis
|
|
43
|
+
cd My_Thesis
|
|
44
|
+
vim main.tex
|
|
45
|
+
olcli diff # what would change on Overleaf
|
|
46
|
+
olcli push # upload your edits
|
|
47
|
+
olcli pdf # compile on Overleaf and download the PDF
|
|
61
48
|
```
|
|
62
49
|
|
|
63
|
-
|
|
50
|
+
`olcli auth --browser` opens the login page in Chrome, Edge, Chromium or Brave with a new temporary profile (never your own), waits until you have signed in, and keeps only the session cookie. It works with SSO, Google, ORCID and two-factor logins, and olcli never sees your password. It needs Node 22 or newer; set `OLCLI_BROWSER` when your browser is not found.
|
|
64
51
|
|
|
65
|
-
|
|
66
|
-
npx @aloth/olcli list
|
|
67
|
-
```
|
|
52
|
+
### Sign in with a session cookie
|
|
68
53
|
|
|
69
|
-
|
|
54
|
+
No supported browser, or a server without a display? Paste the cookie instead:
|
|
70
55
|
|
|
71
56
|
```bash
|
|
72
|
-
|
|
57
|
+
olcli auth --cookie # prompts, input stays hidden
|
|
58
|
+
pbpaste | olcli auth --cookie - # or read it from stdin
|
|
59
|
+
olcli auth status # instance, account, where the credential comes from
|
|
73
60
|
```
|
|
74
61
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
### 1. Authenticate
|
|
62
|
+
**Get your session cookie:** sign in to Overleaf in a browser, open the developer tools (F12), then Application (Chrome, Edge) or Storage (Firefox), Cookies, and copy the value of `overleaf_session2` (`overleaf.sid` on most self-hosted instances). A value on the command line also works but lands in your shell history.
|
|
78
63
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
olcli auth --cookie "your_session_cookie_value"
|
|
83
|
-
```
|
|
64
|
+
Self-hosted instances without reCAPTCHA also accept `olcli auth --email you@example.com`, which prompts for the password. Scripts can set `OVERLEAF_SESSION`, or `OVERLEAF_EMAIL` and `OVERLEAF_PASSWORD`, and skip `olcli auth` entirely.
|
|
84
65
|
|
|
85
|
-
|
|
66
|
+
### Self-hosted Overleaf
|
|
86
67
|
|
|
87
68
|
```bash
|
|
88
|
-
olcli
|
|
89
|
-
|
|
69
|
+
olcli config set-url https://latex.example.org
|
|
70
|
+
olcli config set-cookie-name overleaf.sid
|
|
71
|
+
olcli auth --browser
|
|
90
72
|
```
|
|
91
73
|
|
|
92
|
-
The
|
|
93
|
-
cookie is saved either way and is what later commands use; the password only
|
|
94
|
-
buys an automatic re-login once that cookie expires. For scripts, set
|
|
95
|
-
`OVERLEAF_EMAIL` and `OVERLEAF_PASSWORD` — every command reads them, so a
|
|
96
|
-
scripted run never needs `olcli auth` at all.
|
|
74
|
+
Or per command: `olcli --base-url https://latex.example.org list`. The MCP server and the git remote helper read `OVERLEAF_BASE_URL` and `OVERLEAF_COOKIE_NAME`.
|
|
97
75
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
olcli list
|
|
102
|
-
```
|
|
76
|
+
## Features
|
|
103
77
|
|
|
104
|
-
|
|
78
|
+
- **Pull, push, sync** with nested folders, local deletions propagated on `sync`, and LaTeX build artifacts ignored ([ignore rules](docs/CONFIGURATION.md#ignoring-files))
|
|
79
|
+
- **Diff** local files against the live project before you push, with `--exit-code` for CI ([docs/DIFF.md](docs/DIFF.md))
|
|
80
|
+
- **Marked-up revisions:** `olcli diff --latexdiff --pdf` builds the struck-through and underlined PDF advisors and journals ask for, compiled on Overleaf, no local TeX needed (needs `latexdiff` on PATH)
|
|
81
|
+
- **Compile and download** the PDF, a single root document (`-r appendix.tex`), or compile outputs such as `.bbl` for arXiv
|
|
82
|
+
- **Files:** upload, download, delete, rename and move by path; download the project as a zip
|
|
83
|
+
- **Review comments:** list, add, reply, resolve, reopen and delete comment threads
|
|
84
|
+
- **Tracked changes:** list suggested insertions and deletions, accept or reject them. Track changes is an Overleaf premium feature: it is only available in projects whose owner has a premium plan, and invited collaborators on any plan can then use it. In other projects there are no tracked changes to list
|
|
85
|
+
- **Projects:** create, rename, and bulk-rename by pattern (dry run unless `--apply`)
|
|
86
|
+
- **Git remote:** `git clone overleaf::https://www.overleaf.com/project/<id>` ([docs/GIT-REMOTE.md](docs/GIT-REMOTE.md))
|
|
87
|
+
- **MCP server** for AI agents; every tool that writes asks you first ([docs/MCP.md](docs/MCP.md))
|
|
88
|
+
- **Forgiving project names:** case-insensitive, unique prefixes, "Did you mean" suggestions
|
|
89
|
+
- **Scriptable:** `--json` on listings, plain output when piped, `NO_COLOR`, exit codes that mean something
|
|
105
90
|
|
|
106
|
-
|
|
107
|
-
olcli pull "My Thesis"
|
|
108
|
-
cd My_Thesis/
|
|
109
|
-
vim main.tex
|
|
110
|
-
olcli push
|
|
111
|
-
```
|
|
91
|
+
## Use with Claude Code, Codex and Cursor
|
|
112
92
|
|
|
113
|
-
|
|
93
|
+
olcli ships an MCP server, `olcli-mcp`. Add it to `.mcp.json` (Claude Code), `.cursor/mcp.json` (Cursor) or your client's MCP settings:
|
|
114
94
|
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"overleaf": {
|
|
99
|
+
"command": "npx",
|
|
100
|
+
"args": ["-y", "--package", "@aloth/olcli", "olcli-mcp"]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
119
104
|
```
|
|
120
105
|
|
|
121
|
-
|
|
106
|
+
Codex uses TOML in `~/.codex/config.toml` (or `.codex/config.toml` in a trusted project):
|
|
122
107
|
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
git push
|
|
108
|
+
```toml
|
|
109
|
+
[mcp_servers.overleaf]
|
|
110
|
+
command = "npx"
|
|
111
|
+
args = ["-y", "--package", "@aloth/olcli", "olcli-mcp"]
|
|
128
112
|
```
|
|
129
113
|
|
|
130
|
-
|
|
114
|
+
The server uses the session stored by `olcli auth`; set `OVERLEAF_SESSION` in `env` instead if you prefer. Every tool that changes a project (push a file, delete, rename, comment, accept or reject tracked changes, create a project) shows you what it will do and writes only after you confirm it in the client. The server tells the agent that project content, such as comments and document text, is data and not instructions. Details, the full tool list and clients without confirmation support: [docs/MCP.md](docs/MCP.md).
|
|
131
115
|
|
|
132
116
|
## Commands
|
|
133
117
|
|
|
134
|
-
|
|
118
|
+
Inside a pulled directory (it contains `.olcli.json`), the project argument can be left out. `olcli <command> --help` shows every option with examples.
|
|
135
119
|
|
|
136
120
|
| Command | Description |
|
|
137
121
|
|---------|-------------|
|
|
138
|
-
| `olcli auth` |
|
|
139
|
-
| `olcli
|
|
140
|
-
| `olcli logout` | Clear
|
|
141
|
-
| `olcli list` | List
|
|
142
|
-
| `olcli info [project]` |
|
|
143
|
-
| `olcli
|
|
144
|
-
| `olcli
|
|
145
|
-
| `olcli
|
|
146
|
-
| `olcli
|
|
147
|
-
| `olcli
|
|
148
|
-
| `olcli
|
|
149
|
-
| `olcli
|
|
150
|
-
| `olcli
|
|
151
|
-
| `olcli
|
|
152
|
-
| `olcli
|
|
153
|
-
| `olcli project
|
|
154
|
-
| `olcli
|
|
155
|
-
| `olcli
|
|
156
|
-
| `olcli
|
|
157
|
-
| `olcli
|
|
158
|
-
| `olcli comments list [project]` | List comments (`--status`, `--context`, `--
|
|
159
|
-
| `olcli
|
|
160
|
-
| `olcli
|
|
161
|
-
| `olcli comments
|
|
162
|
-
| `olcli
|
|
163
|
-
| `olcli
|
|
164
|
-
| `olcli
|
|
165
|
-
| `olcli
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
> **Tracked changes are an Overleaf premium feature.** They are only available in projects whose owner has a premium plan; invited collaborators can then use them regardless of their own plan. In other projects there are no tracked changes, so `--changes` returns an empty list and `changes accept`/`changes reject` report the ids as not found. See the [Overleaf documentation](https://docs.overleaf.com/collaborating/track-changes) for details.
|
|
176
|
-
|
|
177
|
-
### Compile Options
|
|
178
|
-
|
|
179
|
-
The compile-related commands (`compile`, `pdf`, `output`) accept:
|
|
180
|
-
|
|
181
|
-
| Flag | Description |
|
|
182
|
-
|------|-------------|
|
|
183
|
-
| `-r, --resource <path>` | Compile a specific `.tex` file as the root document (e.g. `appendix.tex`, `folder/test.tex`) |
|
|
184
|
-
|
|
185
|
-
Useful in multi-doc projects: each `-r` run compiles the file as if it were the main document.
|
|
186
|
-
|
|
187
|
-
### Global Options
|
|
188
|
-
|
|
189
|
-
| Flag | Description |
|
|
190
|
-
|------|-------------|
|
|
191
|
-
| `--verbose` | Print HTTP requests and responses to stderr |
|
|
192
|
-
| `--base-url <url>` | Override Overleaf instance URL |
|
|
193
|
-
| `--cookie-name <name>` | Override session cookie name |
|
|
194
|
-
| `--timeout <ms>` | Override HTTP timeout (default: 10000) |
|
|
195
|
-
|
|
196
|
-
## Sync Behavior
|
|
197
|
-
|
|
198
|
-
### Pull
|
|
199
|
-
- Downloads all files from Overleaf
|
|
200
|
-
- Skips local files modified after last pull (won't overwrite your changes)
|
|
201
|
-
- Use `--force` to overwrite local changes
|
|
202
|
-
|
|
203
|
-
### Push
|
|
204
|
-
- Uploads files modified after last pull
|
|
205
|
-
- Preserves nested folder structure
|
|
206
|
-
- Filters out LaTeX build artifacts and OS noise
|
|
207
|
-
- Use `--all` to upload all files, `--dry-run` to preview
|
|
208
|
-
|
|
209
|
-
### Sync
|
|
210
|
-
- Pulls remote changes, then pushes local changes
|
|
211
|
-
- Local modifications win if newer
|
|
212
|
-
- **Propagates local deletions** — use `--no-delete` to opt out
|
|
213
|
-
- Use `--dry-run` to preview without applying
|
|
214
|
-
|
|
215
|
-
### Diff
|
|
216
|
-
|
|
217
|
-
`olcli diff` compares the bytes of your local files against the project's
|
|
218
|
-
current contents and prints a unified diff.
|
|
219
|
-
|
|
220
|
-
```bash
|
|
221
|
-
olcli diff # every changed file, as patches
|
|
222
|
-
olcli diff --name-only # just the changed paths
|
|
223
|
-
olcli diff --file main.tex # one file
|
|
224
|
-
olcli diff -U 8 # wider context
|
|
225
|
-
olcli diff --exit-code # exit 1 if anything differs, for CI
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
**The remote side is fetched fresh on every run.** The diff describes the
|
|
229
|
-
project as it is at that moment — which is what a subsequent `push` would
|
|
230
|
-
overwrite — not a comparison against your last `pull`. `.olcli.json` records
|
|
231
|
-
remote *paths*, never remote *contents*, so there is no stored snapshot to
|
|
232
|
-
compare against; and the whole project arrives in a single request, the same
|
|
233
|
-
one `pull` makes, so fetching fresh costs one round trip rather than one per
|
|
234
|
-
file. A collaborator editing between `diff` and `push` can still change the
|
|
235
|
-
outcome, which is why the fetch time is printed.
|
|
236
|
-
|
|
237
|
-
In the output, `a/` is the remote and `b/` is local: a `+` line is content
|
|
238
|
-
`push` would upload, a `-` line is content it would overwrite. Files that
|
|
239
|
-
differ only in bytes that are not text (PDFs, images) are reported as
|
|
240
|
-
`Binary files ... differ`. Both sides pass through the same ignore layers, so
|
|
241
|
-
build artifacts sitting on Overleaf are not reported as locally deleted.
|
|
242
|
-
|
|
243
|
-
`diff --name-only` and `push --dry-run` answer different questions and will
|
|
244
|
-
disagree. `push --dry-run` lists files whose **modification time** is newer
|
|
245
|
-
than the last pull, because that is what `push` uploads; `diff` lists files
|
|
246
|
-
whose **contents** actually differ. A file you touched without editing appears
|
|
247
|
-
in the first and not the second.
|
|
248
|
-
|
|
249
|
-
#### Marked-up revisions with latexdiff
|
|
250
|
-
|
|
251
|
-
A unified diff is the right artifact for a developer and the wrong one for a
|
|
252
|
-
thesis advisor. `--latexdiff` marks the same revision up inside the document
|
|
253
|
-
instead — deletions struck through, additions underlined — which is what
|
|
254
|
-
advisors and journals ask for.
|
|
255
|
-
|
|
256
|
-
```bash
|
|
257
|
-
olcli diff --latexdiff # write .olcli-diff/main-diff.tex
|
|
258
|
-
olcli diff --latexdiff --pdf # ...and compile it, download .olcli-diff/main-diff.pdf
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Requires `latexdiff` on your PATH. It ships with TeX Live and MacTeX; nothing
|
|
262
|
-
else in `olcli diff` needs an external tool.
|
|
263
|
-
|
|
264
|
-
**`--pdf` compiles on Overleaf, so you do not need a local TeX installation.**
|
|
265
|
-
The compile endpoint can only build a file that is in the project, so the
|
|
266
|
-
marked-up document is uploaded as `olcli-latexdiff.tex` next to your root
|
|
267
|
-
document, compiled, downloaded, and then removed. The command says so before it
|
|
268
|
-
does it, refuses to overwrite a file of that name if one already exists, and
|
|
269
|
-
prints the exact `olcli rm` command if the cleanup itself fails.
|
|
270
|
-
|
|
271
|
-
`\input` and `\include` are inlined before comparing (`--no-flatten` to opt
|
|
272
|
-
out). Without that, a remote compile would resolve those against the files
|
|
273
|
-
sitting in the project — the old content — and quietly produce a PDF showing
|
|
274
|
-
every input file as unchanged.
|
|
275
|
-
|
|
276
|
-
Output goes to `.olcli-diff/`, which is dotted so that `push` and `sync` never
|
|
277
|
-
pick it up; `-o <path>` puts it elsewhere. The root document is the `.tex` file
|
|
278
|
-
declaring `\documentclass`; if several do, `--main <path>` picks one rather
|
|
279
|
-
than the command guessing. `--latexdiff-opt` passes anything else straight
|
|
280
|
-
through, e.g. `--latexdiff-opt --math-markup=0`.
|
|
281
|
-
|
|
282
|
-
One limit worth knowing: `--pdf` compiles against the project, not against your
|
|
283
|
-
working directory, so anything the markup needs must already be on Overleaf. A
|
|
284
|
-
`.sty` or `.cls` you added locally fails the compile — the compiler log is
|
|
285
|
-
written next to the marked-up source when that happens. A *figure* you added
|
|
286
|
-
locally does not fail it; Overleaf draws a placeholder box naming the missing
|
|
287
|
-
file and the rest of the PDF is fine.
|
|
288
|
-
|
|
289
|
-
#### Using `diff` as a CI gate
|
|
290
|
-
|
|
291
|
-
`--exit-code` turns the command into a check, with the statuses `diff(1)` uses:
|
|
292
|
-
|
|
293
|
-
| Status | Meaning |
|
|
294
|
-
|--------|---------|
|
|
295
|
-
| `0` | Nothing differs |
|
|
296
|
-
| `1` | Something differs |
|
|
297
|
-
| `2` | The run failed — bad flags, no session, project unreachable |
|
|
298
|
-
|
|
299
|
-
```yaml
|
|
300
|
-
- name: Fail if the paper on Overleaf has drifted from the repo
|
|
301
|
-
run: olcli diff --exit-code --name-only
|
|
302
|
-
env:
|
|
303
|
-
OVERLEAF_SESSION: ${{ secrets.OVERLEAF_SESSION }}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
**The `1` versus `2` split is the point of the flag.** Without it a pipeline
|
|
307
|
-
cannot tell a changed file from an expired session cookie, and a job that goes
|
|
308
|
-
red for the second reason sends whoever reads the log hunting for a diff that
|
|
309
|
-
was never computed. Every other olcli command reports failure as `1`, and
|
|
310
|
-
`olcli diff` still does when `--exit-code` is absent, so adding the flag does
|
|
311
|
-
not change what existing scripts see.
|
|
312
|
-
|
|
313
|
-
The gate covers whatever was compared: `--file main.tex` narrows it to one
|
|
314
|
-
file, the way a `git diff --exit-code` pathspec does, and a `--file` that
|
|
315
|
-
matches nothing is `0` rather than an error. Under `--latexdiff` it still
|
|
316
|
-
reports on the project as a whole — a changed figure is a real difference even
|
|
317
|
-
though a marked-up root document cannot show it.
|
|
318
|
-
|
|
319
|
-
Note that this compares against Overleaf **now**, not against your last pull,
|
|
320
|
-
so the check is "has anyone drifted from what is committed here", which is what
|
|
321
|
-
makes it worth running on a schedule as well as on a push.
|
|
322
|
-
|
|
323
|
-
#### How deletion propagation works
|
|
324
|
-
|
|
325
|
-
`olcli` records a manifest of remote files in `.olcli.json`. On next sync:
|
|
326
|
-
|
|
327
|
-
- File missing locally + still on remote → deleted on Overleaf
|
|
328
|
-
- File new locally → uploaded
|
|
329
|
-
- File modified locally → uploaded (local wins)
|
|
330
|
-
- File only on remote → downloaded
|
|
331
|
-
|
|
332
|
-
First-time syncs skip the deletion phase (no prior manifest to compare).
|
|
333
|
-
|
|
334
|
-
## Ignoring Files
|
|
335
|
-
|
|
336
|
-
### Three layers
|
|
337
|
-
|
|
338
|
-
| Layer | Source | Purpose |
|
|
339
|
-
|---|---|---|
|
|
340
|
-
| 1 | Built-in | LaTeX intermediates, OS noise, build dirs. Always on. |
|
|
341
|
-
| 2 | `.olignore` | Project-level patterns (gitignore syntax). |
|
|
342
|
-
| 3 | `.olignore.local` | Machine-specific patterns. |
|
|
343
|
-
|
|
344
|
-
Later layers override earlier ones. Negation (`!important.aux`) is supported.
|
|
345
|
-
|
|
346
|
-
### Special PDF rule
|
|
347
|
-
|
|
348
|
-
`X.pdf` is ignored only if `X.tex` (or `.ltx`) exists in the same folder.
|
|
349
|
-
|
|
350
|
-
### Inspecting and overriding
|
|
351
|
-
|
|
352
|
-
```bash
|
|
353
|
-
olcli ignored # list patterns in effect
|
|
354
|
-
olcli push --show-ignored # see what was skipped
|
|
355
|
-
olcli sync --no-default-ignore # only .olignore applies
|
|
356
|
-
olcli sync --no-ignore # upload everything
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
## Configuration
|
|
360
|
-
|
|
361
|
-
Credentials are checked in order:
|
|
362
|
-
|
|
363
|
-
1. `OVERLEAF_SESSION` environment variable
|
|
364
|
-
2. `.olauth` file in current directory
|
|
365
|
-
3. Global config — run `olcli check` to see the exact path
|
|
366
|
-
|
|
367
|
-
The global config path is platform-dependent (`conf` resolves it), so it is not
|
|
368
|
-
hardcoded here: on macOS it lands under `~/Library/Preferences/`, on Linux under
|
|
369
|
-
`~/.config/`. `olcli auth` prints the path it wrote to.
|
|
370
|
-
|
|
371
|
-
⚠️ `olcli auth --save-local` writes `.olauth` into the **current directory**,
|
|
372
|
-
which is usually your LaTeX project. Add it to that project's `.gitignore`
|
|
373
|
-
before committing.
|
|
374
|
-
|
|
375
|
-
### What is stored, and how to clear it
|
|
376
|
-
|
|
377
|
-
Everything is stored in plaintext, so it is worth knowing what is on disk:
|
|
378
|
-
|
|
379
|
-
| Credential | Stored by default | Where |
|
|
380
|
-
|---|---|---|
|
|
381
|
-
| Session cookie | yes | global config, or `.olauth` with `--save-local` |
|
|
382
|
-
| Email + password | **no** — only with `--save-password` | global config |
|
|
383
|
-
|
|
384
|
-
`olcli check` reports what exists without printing any secret.
|
|
385
|
-
|
|
386
|
-
`olcli logout` clears the global config **and** the `.olauth` file in the
|
|
387
|
-
current directory, then lists what it removed. It cannot unset environment
|
|
388
|
-
variables, so if `OVERLEAF_SESSION` or `OVERLEAF_EMAIL`/`OVERLEAF_PASSWORD` are
|
|
389
|
-
set, it says so instead of implying you are logged out — those take precedence
|
|
390
|
-
over anything on disk.
|
|
391
|
-
|
|
392
|
-
### Self-hosted Overleaf
|
|
393
|
-
|
|
394
|
-
```bash
|
|
395
|
-
olcli config set-url https://latex.example.org
|
|
396
|
-
olcli config set-cookie-name overleaf.sid
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
Or pass per-command: `olcli --base-url https://latex.example.org list`
|
|
400
|
-
|
|
401
|
-
### Timeout
|
|
402
|
-
|
|
403
|
-
```bash
|
|
404
|
-
olcli config set-timeout 60000 # persist
|
|
405
|
-
olcli --timeout 60000 pull "Big Thesis" # one-off
|
|
406
|
-
export OVERLEAF_TIMEOUT=60000 # env var
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
Precedence: `--timeout` > `OVERLEAF_TIMEOUT` > config > default (10000ms).
|
|
410
|
-
|
|
411
|
-
### Environment variables
|
|
412
|
-
|
|
413
|
-
olcli reads these. The MCP server and the git remote helper read the same session, password and cookie name variables. Where a flag exists, the flag takes precedence over the variable, and the variable over the stored config.
|
|
414
|
-
|
|
415
|
-
| Variable | Purpose |
|
|
416
|
-
|---|---|
|
|
417
|
-
| `OVERLEAF_SESSION` | Session cookie value |
|
|
418
|
-
| `OVERLEAF_EMAIL`, `OVERLEAF_PASSWORD` | Password login, used when no session cookie is set or it is rejected |
|
|
419
|
-
| `OVERLEAF_BASE_URL` | Instance URL, like `--base-url` (default: `https://www.overleaf.com`) |
|
|
420
|
-
| `OVERLEAF_COOKIE_NAME` | Session cookie name, like `--cookie-name` (default: `overleaf_session2`; self-hosted instances often use `overleaf.sid`) |
|
|
421
|
-
| `OVERLEAF_TIMEOUT` | HTTP timeout in milliseconds, like `--timeout` |
|
|
422
|
-
| `OLCLI_CONCURRENCY` | Documents fetched in parallel by `comments list`, 1 to 8 (default: 4); `--concurrency` takes precedence |
|
|
423
|
-
| `OLCLI_MCP_UNCONFIRMED_WRITES` | MCP server only: `1` turns off write confirmation, see [docs/MCP.md](docs/MCP.md#write-confirmation) |
|
|
424
|
-
| `GIT_REMOTE_OVERLEAF_DEBUG` | Git remote helper only: `1` prints protocol debug output, see [docs/GIT-REMOTE.md](docs/GIT-REMOTE.md#debugging) |
|
|
122
|
+
| `olcli auth` | Sign in: `--browser`, `--cookie`, or `--email` |
|
|
123
|
+
| `olcli auth status` | Instance, account, credential source; exits 1 when not signed in |
|
|
124
|
+
| `olcli logout` | Clear stored credentials |
|
|
125
|
+
| `olcli list` | List projects (`--json`, `-n`) |
|
|
126
|
+
| `olcli info [project]` | Project details and file list |
|
|
127
|
+
| `olcli project create <name>` | Create a blank or example project (`--template`) |
|
|
128
|
+
| `olcli project rename <new> [project]` | Rename the project itself |
|
|
129
|
+
| `olcli project rename-bulk` | Rename many projects by pattern (dry run unless `--apply`) |
|
|
130
|
+
| `olcli pull [project] [dir]` | Download project files |
|
|
131
|
+
| `olcli push [dir]` | Upload local changes (`--dry-run`, `--all`, `--delete`) |
|
|
132
|
+
| `olcli sync [dir]` | Pull then push, propagating local deletions (`--no-delete`, `--dry-run`) |
|
|
133
|
+
| `olcli diff [project] [dir]` | Content diff against the live project (`--name-only`, `--exit-code`, `--latexdiff`, `--pdf`) |
|
|
134
|
+
| `olcli upload <file> [project]` | Upload one file (`--to <path>`) |
|
|
135
|
+
| `olcli download <file> [project]` | Download one file (`-o`) |
|
|
136
|
+
| `olcli delete <file> [project]` | Delete a file or folder (alias `rm`) |
|
|
137
|
+
| `olcli rename <old> <new> [project]` | Rename or move a file or folder (alias `mv`) |
|
|
138
|
+
| `olcli zip [project]` | Download the project as a zip archive |
|
|
139
|
+
| `olcli compile [project]` | Compile on Overleaf (`-r <root.tex>`) |
|
|
140
|
+
| `olcli pdf [project]` | Compile and download the PDF (`-o`, `-r`) |
|
|
141
|
+
| `olcli output [type]` | Download compile outputs such as `bbl` or `log` (`--list`) |
|
|
142
|
+
| `olcli comments list [project]` | List comments (`--status`, `--context`, `--changes`, `--json`) |
|
|
143
|
+
| `olcli comments add <file> <message>` | Comment on selected text |
|
|
144
|
+
| `olcli comments reply <id> <body>` | Reply to a thread |
|
|
145
|
+
| `olcli comments resolve <id>` | Resolve a thread (`reopen` and `delete` too) |
|
|
146
|
+
| `olcli changes accept <ids...>` | Accept tracked changes (premium projects) |
|
|
147
|
+
| `olcli changes reject <ids...>` | Reject tracked changes; preview unless `--yes` |
|
|
148
|
+
| `olcli config set-url <url>` | Set the instance URL (`get-url`, `set-cookie-name`, `set-timeout`) |
|
|
149
|
+
| `olcli ignored [dir]` | Show the ignore patterns in effect |
|
|
150
|
+
|
|
151
|
+
Global options: `--base-url <url>`, `--cookie-name <name>`, `--timeout <ms>`, `--verbose` (print every HTTP request), `--no-color`.
|
|
152
|
+
|
|
153
|
+
## How sync works
|
|
154
|
+
|
|
155
|
+
- `pull` downloads every file and skips local files changed since the last pull; `--force` overwrites them.
|
|
156
|
+
- `push` uploads files changed since the last pull and keeps the folder structure. `push --dry-run` lists them; `olcli diff` shows what actually differs.
|
|
157
|
+
- `sync` pulls, then pushes. Local edits win when they are newer, and a file you deleted locally is deleted on Overleaf (`--no-delete` to opt out; `sync --dry-run --verbose` to preview).
|
|
158
|
+
- Before a push, `olcli diff` compares against the project as it is on Overleaf right now, so you see a coauthor's newer edit before you overwrite it.
|
|
425
159
|
|
|
426
160
|
## Examples
|
|
427
161
|
|
|
428
162
|
```bash
|
|
429
163
|
# Daily thesis workflow
|
|
430
164
|
olcli pull "PhD Thesis" thesis && cd thesis
|
|
431
|
-
vim chapters/methods.tex
|
|
432
165
|
olcli sync && olcli pdf -o draft.pdf
|
|
433
166
|
|
|
434
|
-
#
|
|
435
|
-
olcli
|
|
167
|
+
# Marked-up PDF of your local revision for your advisor
|
|
168
|
+
olcli diff --latexdiff --pdf
|
|
436
169
|
|
|
437
|
-
#
|
|
438
|
-
olcli
|
|
439
|
-
olcli compile "Conference Paper" -r folder/test.tex
|
|
170
|
+
# Fail a CI job when the paper on Overleaf drifted from the repository
|
|
171
|
+
olcli diff --exit-code --name-only
|
|
440
172
|
|
|
441
|
-
#
|
|
442
|
-
olcli
|
|
443
|
-
olcli upload /tmp/build/diagram.png # absolute path lands in the project root
|
|
444
|
-
olcli upload /tmp/build/diagram.png --to figures/diagram.png # explicit destination
|
|
173
|
+
# Review comments, with two lines of context
|
|
174
|
+
olcli comments list --status open --context 2
|
|
445
175
|
|
|
446
176
|
# arXiv submission prep
|
|
447
177
|
olcli output bbl -o main.bbl
|
|
448
|
-
olcli output bbl -r folder/test.tex -o main.bbl # compile artifacts from a specific root doc
|
|
449
178
|
olcli zip -o arxiv-submission.zip
|
|
450
179
|
|
|
451
|
-
#
|
|
180
|
+
# Back up every project
|
|
452
181
|
for proj in $(olcli list --json | jq -r '.[].name'); do
|
|
453
182
|
olcli zip "$proj" -o "backups/${proj}.zip"
|
|
454
183
|
done
|
|
455
184
|
```
|
|
456
185
|
|
|
457
|
-
##
|
|
458
|
-
|
|
459
|
-
`@aloth/olcli` exposes `OverleafClient` and all public interfaces as a library.
|
|
186
|
+
## Proxy
|
|
460
187
|
|
|
461
|
-
|
|
188
|
+
olcli honors `HTTPS_PROXY`, `HTTP_PROXY`, `ALL_PROXY` and `NO_PROXY` (lower-case names take precedence) for every request. https:// instances are reached through a CONNECT tunnel, so the proxy never sees the session cookie. `localhost` and loopback addresses are always reached directly. `--verbose` names the proxy used for each request.
|
|
462
189
|
|
|
463
190
|
```bash
|
|
464
|
-
|
|
191
|
+
HTTPS_PROXY=http://proxy.example.org:3128 olcli list
|
|
465
192
|
```
|
|
466
193
|
|
|
467
|
-
|
|
194
|
+
## Configuration and credentials
|
|
195
|
+
|
|
196
|
+
Credentials are read in this order: `OVERLEAF_SESSION`, then `.olauth` in the current directory (written by `olcli auth --save-local`), then the global config. `olcli auth status` shows which one is used and where it lives. The session cookie is stored in plaintext; a password only when you pass `--save-password`. `olcli logout` clears the global config and `.olauth`.
|
|
197
|
+
|
|
198
|
+
Every environment variable, the timeout setting and the ignore rules (`.olignore`, `.olignore.local`) are described in [docs/CONFIGURATION.md](docs/CONFIGURATION.md). `olcli --help` lists the variables too.
|
|
199
|
+
|
|
200
|
+
## Library
|
|
468
201
|
|
|
469
202
|
```ts
|
|
470
203
|
import { OverleafClient } from '@aloth/olcli';
|
|
471
204
|
|
|
472
205
|
const client = await OverleafClient.fromSessionCookie(cookie);
|
|
473
|
-
|
|
474
|
-
const created = await client.createProject('My Paper');
|
|
475
206
|
const projects = await client.listProjects();
|
|
476
|
-
const
|
|
477
|
-
const zipBuf = await client.downloadProject(projectId);
|
|
478
|
-
const pdfBuf = await client.downloadPdf(projectId);
|
|
479
|
-
|
|
480
|
-
await client.uploadFile(projectId, null, 'main.tex', readFileSync('main.tex'));
|
|
481
|
-
|
|
482
|
-
const comments = await client.listComments(projectId, { status: 'open' });
|
|
207
|
+
const pdf = await client.downloadPdf(projects[0].id);
|
|
483
208
|
```
|
|
484
209
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
```ts
|
|
488
|
-
import {
|
|
489
|
-
OverleafClient,
|
|
490
|
-
// Types
|
|
491
|
-
Project, ProjectInfo, ProjectTemplate, CreateProjectOptions, CreatedProject,
|
|
492
|
-
FolderEntry, DocEntry, FileEntry,
|
|
493
|
-
CommentMessage, ProjectComment, CommentContext, CommentStatus,
|
|
494
|
-
ListCommentsOptions, AddCommentOptions, Credentials, SessionCookiePair,
|
|
495
|
-
// Config utilities
|
|
496
|
-
getBaseUrl, setBaseUrl, getSessionCookie, setSessionCookie,
|
|
497
|
-
getSessionCookieName, setSessionCookieName, getCsrf, setCsrf,
|
|
498
|
-
getLastProject, setLastProject, clearConfig, getConfigPath, saveOlAuth,
|
|
499
|
-
getTimeout, setTimeout, getPasswordCredentials, setPasswordCredentials,
|
|
500
|
-
clearPasswordCredentials, type PasswordCredentials,
|
|
501
|
-
// Ignore utilities
|
|
502
|
-
DEFAULT_IGNORE_PATTERNS, loadIgnore, shouldIgnore, buildTexSiblingSet,
|
|
503
|
-
IgnoreContext, LoadIgnoreOptions,
|
|
504
|
-
} from '@aloth/olcli';
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
## Further Documentation
|
|
508
|
-
|
|
509
|
-
- [MCP Server](docs/MCP.md) — AI assistant integration (Claude, Cursor, Windsurf)
|
|
510
|
-
- Tools that change a project ask you to confirm through MCP elicitation and write nothing without it; clients without elicitation get a preview and the `olcli` command to run instead. `OLCLI_MCP_UNCONFIRMED_WRITES=1` turns this off. See [Write confirmation](docs/MCP.md#write-confirmation)
|
|
511
|
-
- [Git Remote Helper](docs/GIT-REMOTE.md) — use Overleaf as a native git remote
|
|
210
|
+
All exports: [docs/LIBRARY.md](docs/LIBRARY.md).
|
|
512
211
|
|
|
513
212
|
## Troubleshooting
|
|
514
213
|
|
|
515
|
-
**Session expired
|
|
214
|
+
- **"Session expired or invalid. Run: olcli auth"**: sessions expire; sign in again. `olcli auth status` tells you which credential was used.
|
|
215
|
+
- **Timeouts on large projects:** `olcli config set-timeout 60000`, or `--timeout 60000` once.
|
|
216
|
+
- **Compilation fails:** the Overleaf web editor shows the full log; `olcli output log` downloads it.
|
|
217
|
+
- **Anything else:** run the command with `--verbose` and include the output (without the cookie) in an issue.
|
|
516
218
|
|
|
517
|
-
|
|
219
|
+
## Documentation
|
|
518
220
|
|
|
519
|
-
|
|
221
|
+
- [docs/DIFF.md](docs/DIFF.md): diff, latexdiff and the CI gate
|
|
222
|
+
- [docs/MCP.md](docs/MCP.md): MCP server, tools and write confirmation
|
|
223
|
+
- [docs/GIT-REMOTE.md](docs/GIT-REMOTE.md): Overleaf as a git remote
|
|
224
|
+
- [docs/CONFIGURATION.md](docs/CONFIGURATION.md): credentials, environment variables, timeout, ignore rules
|
|
225
|
+
- [docs/LIBRARY.md](docs/LIBRARY.md): TypeScript library
|
|
226
|
+
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): how the client talks to Overleaf (there is no public Overleaf API, so it uses a browser session)
|
|
520
227
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup, which tests need a real
|
|
524
|
-
Overleaf account, and what to expect from CI on a pull request.
|
|
228
|
+
## Contributing
|
|
525
229
|
|
|
526
|
-
[
|
|
527
|
-
there is no public Overleaf API, so it authenticates as a browser session.
|
|
230
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup, which tests need a real Overleaf account, and what CI checks on a pull request.
|
|
528
231
|
|
|
529
232
|
## License
|
|
530
233
|
|