overleaf-codex 0.1.0-rc.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.
Potentially problematic release.
This version of overleaf-codex might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/NOTICE.md +25 -0
- package/README.md +217 -0
- package/assets/olcx-mark.svg +22 -0
- package/dist/auth/projectAuth.d.ts +19 -0
- package/dist/auth/projectAuth.js +163 -0
- package/dist/auth/projectAuth.js.map +1 -0
- package/dist/auth/redact.d.ts +3 -0
- package/dist/auth/redact.js +7 -0
- package/dist/auth/redact.js.map +1 -0
- package/dist/auth/types.d.ts +10 -0
- package/dist/auth/types.js +4 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/backend/index.d.ts +6 -0
- package/dist/backend/index.js +2 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/olcli/client.d.ts +329 -0
- package/dist/backend/olcli/client.js +1757 -0
- package/dist/backend/olcli/client.js.map +1 -0
- package/dist/backend/olcli/index.d.ts +2 -0
- package/dist/backend/olcli/index.js +2 -0
- package/dist/backend/olcli/index.js.map +1 -0
- package/dist/backend/overleafBackend.d.ts +41 -0
- package/dist/backend/overleafBackend.js +200 -0
- package/dist/backend/overleafBackend.js.map +1 -0
- package/dist/backend/types.d.ts +73 -0
- package/dist/backend/types.js +2 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/cli-behavior.d.ts +14 -0
- package/dist/cli-behavior.js +59 -0
- package/dist/cli-behavior.js.map +1 -0
- package/dist/cli.d.ts +30 -0
- package/dist/cli.js +441 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth.d.ts +21 -0
- package/dist/commands/auth.js +104 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/compile.d.ts +7 -0
- package/dist/commands/compile.js +73 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/doctor.d.ts +11 -0
- package/dist/commands/doctor.js +9 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/endpoint.d.ts +23 -0
- package/dist/commands/endpoint.js +69 -0
- package/dist/commands/endpoint.js.map +1 -0
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.js +48 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.js +5 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +26 -0
- package/dist/commands/sync.js +139 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/watch.d.ts +28 -0
- package/dist/commands/watch.js +124 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/compile/compileFlow.d.ts +32 -0
- package/dist/compile/compileFlow.js +290 -0
- package/dist/compile/compileFlow.js.map +1 -0
- package/dist/compile/pdfOutput.d.ts +12 -0
- package/dist/compile/pdfOutput.js +64 -0
- package/dist/compile/pdfOutput.js.map +1 -0
- package/dist/config/ignoreRules.d.ts +5 -0
- package/dist/config/ignoreRules.js +53 -0
- package/dist/config/ignoreRules.js.map +1 -0
- package/dist/config/overleafProject.d.ts +9 -0
- package/dist/config/overleafProject.js +61 -0
- package/dist/config/overleafProject.js.map +1 -0
- package/dist/config/projectConfig.d.ts +6 -0
- package/dist/config/projectConfig.js +180 -0
- package/dist/config/projectConfig.js.map +1 -0
- package/dist/config/projectRoot.d.ts +1 -0
- package/dist/config/projectRoot.js +36 -0
- package/dist/config/projectRoot.js.map +1 -0
- package/dist/config/types.d.ts +50 -0
- package/dist/config/types.js +34 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/vscode.d.ts +10 -0
- package/dist/config/vscode.js +134 -0
- package/dist/config/vscode.js.map +1 -0
- package/dist/diagnostics/doctor.d.ts +8 -0
- package/dist/diagnostics/doctor.js +209 -0
- package/dist/diagnostics/doctor.js.map +1 -0
- package/dist/diagnostics/status.d.ts +6 -0
- package/dist/diagnostics/status.js +110 -0
- package/dist/diagnostics/status.js.map +1 -0
- package/dist/diagnostics/types.d.ts +33 -0
- package/dist/diagnostics/types.js +2 -0
- package/dist/diagnostics/types.js.map +1 -0
- package/dist/endpoint/overleafEndpoint.d.ts +36 -0
- package/dist/endpoint/overleafEndpoint.js +105 -0
- package/dist/endpoint/overleafEndpoint.js.map +1 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/sync/apply.d.ts +14 -0
- package/dist/sync/apply.js +92 -0
- package/dist/sync/apply.js.map +1 -0
- package/dist/sync/conflicts.d.ts +7 -0
- package/dist/sync/conflicts.js +59 -0
- package/dist/sync/conflicts.js.map +1 -0
- package/dist/sync/ignore.d.ts +5 -0
- package/dist/sync/ignore.js +74 -0
- package/dist/sync/ignore.js.map +1 -0
- package/dist/sync/plan.d.ts +3 -0
- package/dist/sync/plan.js +197 -0
- package/dist/sync/plan.js.map +1 -0
- package/dist/sync/snapshot.d.ts +13 -0
- package/dist/sync/snapshot.js +82 -0
- package/dist/sync/snapshot.js.map +1 -0
- package/dist/sync/state.d.ts +16 -0
- package/dist/sync/state.js +214 -0
- package/dist/sync/state.js.map +1 -0
- package/dist/sync/types.d.ts +113 -0
- package/dist/sync/types.js +4 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/testing/fakeBackend.d.ts +27 -0
- package/dist/testing/fakeBackend.js +213 -0
- package/dist/testing/fakeBackend.js.map +1 -0
- package/dist/watch/queue.d.ts +2 -0
- package/dist/watch/queue.js +91 -0
- package/dist/watch/queue.js.map +1 -0
- package/dist/watch/types.d.ts +52 -0
- package/dist/watch/types.js +2 -0
- package/dist/watch/types.js.map +1 -0
- package/dist/watch/watcher.d.ts +6 -0
- package/dist/watch/watcher.js +58 -0
- package/dist/watch/watcher.js.map +1 -0
- package/dist/watch/workflow.d.ts +30 -0
- package/dist/watch/workflow.js +62 -0
- package/dist/watch/workflow.js.map +1 -0
- package/docs/architecture.md +603 -0
- package/docs/auth.md +65 -0
- package/docs/cli-behavior.md +95 -0
- package/docs/compile.md +51 -0
- package/docs/design.md +82 -0
- package/docs/endpoint.md +84 -0
- package/docs/npm-packaging.md +148 -0
- package/docs/quickdev-queue-audit.md +193 -0
- package/docs/release-gates.md +119 -0
- package/docs/release-notes-v1.md +97 -0
- package/docs/security.md +61 -0
- package/docs/sync-state.md +305 -0
- package/docs/sync.md +50 -0
- package/docs/troubleshooting.md +124 -0
- package/docs/usage.md +184 -0
- package/examples/minimal-paper/.olcx/auth.local.example.json +7 -0
- package/examples/minimal-paper/.olcx/config.json +23 -0
- package/examples/minimal-paper/README.md +88 -0
- package/examples/minimal-paper/main.tex +23 -0
- package/package.json +66 -0
- package/src/backend/olcli/LICENSE +21 -0
- package/src/backend/olcli/README.md +26 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Purpose And Contract Status
|
|
4
|
+
|
|
5
|
+
This document is the v1 internal architecture contract for `olcx`. It is a
|
|
6
|
+
repository contract for implementation tasks, not a public npm API guarantee.
|
|
7
|
+
Later tasks should use it to choose module locations, dependency direction,
|
|
8
|
+
stable internal types, path ownership, and backend boundaries.
|
|
9
|
+
|
|
10
|
+
`docs/design.md`, `docs/usage.md`, and `docs/security.md` remain the product,
|
|
11
|
+
workflow, and security context. This document owns internal module boundaries and
|
|
12
|
+
the shared TypeScript interface direction used by implementation tasks.
|
|
13
|
+
|
|
14
|
+
## V1 Principles And Non-Goals
|
|
15
|
+
|
|
16
|
+
- v1 is a lightweight CLI-first implementation.
|
|
17
|
+
- The core workflow must not require a local LaTeX installation.
|
|
18
|
+
- v1 does not include a VS Code extension. The CLI generates and repairs
|
|
19
|
+
`.vscode/settings.json` and `.vscode/tasks.json` during `olcx init`.
|
|
20
|
+
- One local paper repository binds to one Overleaf project by default.
|
|
21
|
+
- Sync must never silently overwrite local or remote changes.
|
|
22
|
+
- Auth is project-local by default and must not store Overleaf passwords.
|
|
23
|
+
- Users install and run `olcx`; they must not need `olcli` as a separate runtime
|
|
24
|
+
tool.
|
|
25
|
+
- `olcx` is not an official Overleaf project and is not an official `olcli`
|
|
26
|
+
project.
|
|
27
|
+
- Normal tests must not require real Overleaf access, local LaTeX, Playwright, or
|
|
28
|
+
browser automation.
|
|
29
|
+
|
|
30
|
+
## Module Boundaries
|
|
31
|
+
|
|
32
|
+
The CLI entry and bootstrap module, currently `src/cli.ts`, owns Commander
|
|
33
|
+
setup, version wiring, top-level process entry, and delegation to command action
|
|
34
|
+
modules. It must not own sync, compile, auth, config, or backend workflow logic.
|
|
35
|
+
|
|
36
|
+
Command modules in `src/commands/*` own option parsing, user-facing output,
|
|
37
|
+
exit-code mapping, and calls into workflow modules. Commands must remain thin and
|
|
38
|
+
must not import backend-private `olcli` code.
|
|
39
|
+
|
|
40
|
+
Config modules in `src/config/*` own project root discovery,
|
|
41
|
+
`.olcx/config.json`, config schema validation, default paths, ignore-rule
|
|
42
|
+
assembly, allowed Overleaf endpoint values, and shareable workflow settings.
|
|
43
|
+
|
|
44
|
+
Auth modules in `src/auth/*` own `.olcx/auth.local.json`, environment-variable
|
|
45
|
+
auth overrides, redaction, local-only persistence, auth status summaries, and
|
|
46
|
+
validation of auth file shape. They must not store passwords.
|
|
47
|
+
|
|
48
|
+
Backend modules in `src/backend/*` own the stable `OverleafBackend` interface and
|
|
49
|
+
all network or private Overleaf implementation details. Imported or adapted
|
|
50
|
+
`olcli` code is backend-private.
|
|
51
|
+
|
|
52
|
+
Endpoint modules in `src/endpoint/*` own the public `www`/`cn` endpoint aliases,
|
|
53
|
+
allowed base URLs, read-only `/project` probing, latency selection, and redacted
|
|
54
|
+
probe failure formatting. Endpoint probing must not use project-specific URLs or
|
|
55
|
+
the backend-private `olcli` client.
|
|
56
|
+
|
|
57
|
+
Sync modules in `src/sync/*` own local and remote snapshots, ignore filtering,
|
|
58
|
+
sync planning, safe application of operations, conflict reports, and sync state
|
|
59
|
+
under `.olcx/state/`.
|
|
60
|
+
|
|
61
|
+
Compile modules in `src/compile/*` own compile orchestration, polling policy, PDF
|
|
62
|
+
download and write behavior, compile logs, timeouts, and fast or draft fallback
|
|
63
|
+
behavior.
|
|
64
|
+
|
|
65
|
+
Watch modules in `src/watch/*` own file watching, debounce, serial queueing,
|
|
66
|
+
failure pause state, and composition of sync plus compile. Watch must reuse the
|
|
67
|
+
same ignore rules and sync semantics as manual `sync`.
|
|
68
|
+
|
|
69
|
+
Diagnostics modules in `src/diagnostics/*` own `status` and `doctor` checks,
|
|
70
|
+
redacted summaries, and user-facing remediation hints.
|
|
71
|
+
|
|
72
|
+
Testing support in `src/testing/*` owns fake backends, temporary paper repository
|
|
73
|
+
helpers, deterministic fixtures, and helpers for CLI-level integration tests.
|
|
74
|
+
|
|
75
|
+
## V1 Source Tree
|
|
76
|
+
|
|
77
|
+
This is the suggested source tree contract for later implementation tasks. This
|
|
78
|
+
documentation task does not create these source files.
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
src/
|
|
82
|
+
cli.ts
|
|
83
|
+
commands/
|
|
84
|
+
auth.ts
|
|
85
|
+
init.ts
|
|
86
|
+
sync.ts
|
|
87
|
+
compile.ts
|
|
88
|
+
watch.ts
|
|
89
|
+
status.ts
|
|
90
|
+
doctor.ts
|
|
91
|
+
endpoint.ts
|
|
92
|
+
config/
|
|
93
|
+
types.ts
|
|
94
|
+
projectRoot.ts
|
|
95
|
+
projectConfig.ts
|
|
96
|
+
ignoreRules.ts
|
|
97
|
+
auth/
|
|
98
|
+
types.ts
|
|
99
|
+
projectAuth.ts
|
|
100
|
+
redact.ts
|
|
101
|
+
backend/
|
|
102
|
+
types.ts
|
|
103
|
+
overleafBackend.ts
|
|
104
|
+
olcli/
|
|
105
|
+
sync/
|
|
106
|
+
endpoint/
|
|
107
|
+
overleafEndpoint.ts
|
|
108
|
+
types.ts
|
|
109
|
+
snapshot.ts
|
|
110
|
+
plan.ts
|
|
111
|
+
apply.ts
|
|
112
|
+
conflicts.ts
|
|
113
|
+
compile/
|
|
114
|
+
types.ts
|
|
115
|
+
compileFlow.ts
|
|
116
|
+
pdfOutput.ts
|
|
117
|
+
watch/
|
|
118
|
+
types.ts
|
|
119
|
+
queue.ts
|
|
120
|
+
watcher.ts
|
|
121
|
+
diagnostics/
|
|
122
|
+
types.ts
|
|
123
|
+
status.ts
|
|
124
|
+
doctor.ts
|
|
125
|
+
testing/
|
|
126
|
+
fakeBackend.ts
|
|
127
|
+
tempProject.ts
|
|
128
|
+
errors.ts
|
|
129
|
+
result.ts
|
|
130
|
+
tests/
|
|
131
|
+
fixtures/
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Stable Internal TypeScript Interfaces
|
|
135
|
+
|
|
136
|
+
These drafts are stable internal contracts for v1 modules. Field additions are
|
|
137
|
+
allowed when later tasks need them, but modules should not rename or bypass these
|
|
138
|
+
shapes without updating this contract.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
export interface ProjectConfig {
|
|
142
|
+
schemaVersion: 1;
|
|
143
|
+
projectId: string;
|
|
144
|
+
projectUrl?: string;
|
|
145
|
+
overleaf: {
|
|
146
|
+
baseUrl: "https://www.overleaf.com" | "https://cn.overleaf.com";
|
|
147
|
+
};
|
|
148
|
+
rootDocument: string;
|
|
149
|
+
pdfPath: string;
|
|
150
|
+
sync: {
|
|
151
|
+
mode: "bidirectional";
|
|
152
|
+
conflictPolicy: "pause";
|
|
153
|
+
ignore?: string[];
|
|
154
|
+
};
|
|
155
|
+
compile: {
|
|
156
|
+
timeoutMs: number;
|
|
157
|
+
fastFallback: {
|
|
158
|
+
enabled: boolean;
|
|
159
|
+
attempts: number;
|
|
160
|
+
timeoutMs: number;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface ProjectAuth {
|
|
166
|
+
schemaVersion: 1;
|
|
167
|
+
accountLabel?: string;
|
|
168
|
+
sessionCookie: string;
|
|
169
|
+
updatedAt: string;
|
|
170
|
+
source: "interactive" | "cli-option" | "env";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface BackendAuthInput {
|
|
174
|
+
auth: ProjectAuth;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface BackendAccount {
|
|
178
|
+
accountLabel?: string;
|
|
179
|
+
authenticated: boolean;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface BackendProjectInput {
|
|
183
|
+
projectId: string;
|
|
184
|
+
auth: ProjectAuth;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface BackendFileInput extends BackendProjectInput {
|
|
188
|
+
path: string;
|
|
189
|
+
remoteId?: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface BackendUploadInput extends BackendProjectInput {
|
|
193
|
+
path: string;
|
|
194
|
+
bytes: Uint8Array;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface BackendCompileInput extends BackendProjectInput {
|
|
198
|
+
timeoutMs: number;
|
|
199
|
+
rootDocument: string;
|
|
200
|
+
fastMode?: boolean;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface OverleafBackend {
|
|
204
|
+
validateAuth(input: BackendAuthInput): Promise<BackendAccount>;
|
|
205
|
+
listFiles(input: BackendProjectInput): Promise<RemoteFile[]>;
|
|
206
|
+
downloadFile(input: BackendFileInput): Promise<Uint8Array>;
|
|
207
|
+
uploadFile(input: BackendUploadInput): Promise<RemoteFile>;
|
|
208
|
+
deleteFile(input: BackendFileInput): Promise<void>;
|
|
209
|
+
compile(input: BackendCompileInput): Promise<CompileResult>;
|
|
210
|
+
downloadPdf(input: BackendProjectInput): Promise<Uint8Array>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export type OverleafBackendFactory = (options: {
|
|
214
|
+
baseUrl?: string;
|
|
215
|
+
cookieName?: string;
|
|
216
|
+
}) => OverleafBackend;
|
|
217
|
+
|
|
218
|
+
export interface RemoteFile {
|
|
219
|
+
path: string;
|
|
220
|
+
kind: "file" | "directory";
|
|
221
|
+
remoteId?: string;
|
|
222
|
+
size?: number;
|
|
223
|
+
contentHash?: string;
|
|
224
|
+
modifiedAt?: string;
|
|
225
|
+
revision?: string;
|
|
226
|
+
binary?: boolean;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface LocalFileSnapshot {
|
|
230
|
+
path: string;
|
|
231
|
+
exists: boolean;
|
|
232
|
+
size?: number;
|
|
233
|
+
contentHash?: string;
|
|
234
|
+
modifiedAt?: string;
|
|
235
|
+
ignored: boolean;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export type SyncOperationType =
|
|
239
|
+
| "upload"
|
|
240
|
+
| "download"
|
|
241
|
+
| "deleteLocal"
|
|
242
|
+
| "deleteRemote"
|
|
243
|
+
| "unchanged"
|
|
244
|
+
| "conflict"
|
|
245
|
+
| "ignored";
|
|
246
|
+
|
|
247
|
+
export interface SyncOperation {
|
|
248
|
+
type: SyncOperationType;
|
|
249
|
+
path: string;
|
|
250
|
+
local?: LocalFileSnapshot;
|
|
251
|
+
remote?: RemoteFile;
|
|
252
|
+
reason: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface SyncConflict {
|
|
256
|
+
path: string;
|
|
257
|
+
reason:
|
|
258
|
+
| "both-modified"
|
|
259
|
+
| "local-modified-remote-deleted"
|
|
260
|
+
| "remote-modified-local-deleted"
|
|
261
|
+
| "unsafe-delete"
|
|
262
|
+
| "unsupported";
|
|
263
|
+
local?: LocalFileSnapshot;
|
|
264
|
+
remote?: RemoteFile;
|
|
265
|
+
recommendation: string;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface SyncPlan {
|
|
269
|
+
projectId: string;
|
|
270
|
+
createdAt: string;
|
|
271
|
+
dryRun: boolean;
|
|
272
|
+
operations: SyncOperation[];
|
|
273
|
+
conflicts: SyncConflict[];
|
|
274
|
+
summary: {
|
|
275
|
+
upload: number;
|
|
276
|
+
download: number;
|
|
277
|
+
deleteLocal: number;
|
|
278
|
+
deleteRemote: number;
|
|
279
|
+
unchanged: number;
|
|
280
|
+
conflict: number;
|
|
281
|
+
ignored: number;
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface CompileLogEntry {
|
|
286
|
+
level: "info" | "warning" | "error";
|
|
287
|
+
message: string;
|
|
288
|
+
file?: string;
|
|
289
|
+
line?: number;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface CompileResult {
|
|
293
|
+
status: "success" | "failure" | "timeout" | "fallback-success";
|
|
294
|
+
projectId: string;
|
|
295
|
+
pdfBytes?: Uint8Array;
|
|
296
|
+
pdfPath?: string;
|
|
297
|
+
logs: CompileLogEntry[];
|
|
298
|
+
warnings: string[];
|
|
299
|
+
elapsedMs: number;
|
|
300
|
+
fallbackUsed: boolean;
|
|
301
|
+
error?: OlcxError;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export type OlcxErrorCode =
|
|
305
|
+
| "USER_INPUT_ERROR"
|
|
306
|
+
| "PROJECT_CONFIG_NOT_FOUND"
|
|
307
|
+
| "PROJECT_CONFIG_INVALID"
|
|
308
|
+
| "PROJECT_AUTH_NOT_FOUND"
|
|
309
|
+
| "PROJECT_AUTH_INVALID"
|
|
310
|
+
| "BACKEND_AUTH_FAILED"
|
|
311
|
+
| "BACKEND_NETWORK_ERROR"
|
|
312
|
+
| "BACKEND_PROTOCOL_ERROR"
|
|
313
|
+
| "SYNC_CONFLICT"
|
|
314
|
+
| "SYNC_UNSAFE_OPERATION"
|
|
315
|
+
| "COMPILE_FAILED"
|
|
316
|
+
| "COMPILE_TIMEOUT"
|
|
317
|
+
| "IO_ERROR"
|
|
318
|
+
| "INTERNAL_ERROR";
|
|
319
|
+
|
|
320
|
+
export interface OlcxError {
|
|
321
|
+
name: "OlcxError";
|
|
322
|
+
code: OlcxErrorCode;
|
|
323
|
+
message: string;
|
|
324
|
+
exitCode: number;
|
|
325
|
+
hint?: string;
|
|
326
|
+
details?: Record<string, unknown>;
|
|
327
|
+
cause?: unknown;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export type Result<T> =
|
|
331
|
+
| { ok: true; value: T }
|
|
332
|
+
| { ok: false; error: OlcxError };
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Field Meanings
|
|
336
|
+
|
|
337
|
+
- `ProjectConfig.overleaf.baseUrl` is the project-local Overleaf endpoint. It is
|
|
338
|
+
restricted to `https://www.overleaf.com` and `https://cn.overleaf.com`.
|
|
339
|
+
- Sync, compile, watch, and CLI workflow modules must pass
|
|
340
|
+
`{ baseUrl: config.overleaf.baseUrl }` into the real backend factory whenever
|
|
341
|
+
they create an `OverleafBackend`. Tests may inject `createBackend` to avoid
|
|
342
|
+
real Overleaf access.
|
|
343
|
+
|
|
344
|
+
- `ProjectConfig.schemaVersion`: config schema version. v1 uses `1`.
|
|
345
|
+
- `ProjectConfig.projectId`: Overleaf project identifier parsed from a URL or
|
|
346
|
+
direct input. It is shareable config, but can still be sensitive in private
|
|
347
|
+
repositories.
|
|
348
|
+
- `ProjectConfig.projectUrl`: optional original project URL using placeholders
|
|
349
|
+
such as `https://www.overleaf.com/project/<overleaf-project-id>`.
|
|
350
|
+
- `ProjectConfig.rootDocument`: primary TeX entry point. Default is `main.tex`.
|
|
351
|
+
- `ProjectConfig.pdfPath`: local PDF output path. Default is
|
|
352
|
+
`build/overleaf/main.pdf`.
|
|
353
|
+
- `ProjectConfig.sync.mode`: v1 sync mode. The only v1 value is
|
|
354
|
+
`bidirectional`.
|
|
355
|
+
- `ProjectConfig.sync.conflictPolicy`: v1 conflict behavior. The only v1 value
|
|
356
|
+
is `pause`.
|
|
357
|
+
- `ProjectConfig.sync.ignore`: user-configured ignore patterns appended to the
|
|
358
|
+
required built-in ignore set.
|
|
359
|
+
- `ProjectConfig.compile.timeoutMs`: normal Overleaf compile timeout budget.
|
|
360
|
+
- `ProjectConfig.compile.fastFallback`: bounded fallback settings for timeout,
|
|
361
|
+
time-limit, or upgrade-limit recovery. Defaults to enabled with one fast/draft
|
|
362
|
+
attempt. The current olcli adapter uses per-request draft mode, so it does not
|
|
363
|
+
persistently change project compile settings; future adapters that use project
|
|
364
|
+
settings must restore them through the backend fast compile session.
|
|
365
|
+
- `ProjectAuth.schemaVersion`: auth file schema version. v1 uses `1`.
|
|
366
|
+
- `ProjectAuth.accountLabel`: optional display label for status output. If it is
|
|
367
|
+
absent, output should display `unknown`.
|
|
368
|
+
- `ProjectAuth.sessionCookie`: opaque local-only Overleaf session value. It must
|
|
369
|
+
never be logged, committed, printed, or written to handoff reports.
|
|
370
|
+
- `ProjectAuth.updatedAt`: ISO timestamp of the last local auth update.
|
|
371
|
+
- `ProjectAuth.source`: how the current local auth value was provided.
|
|
372
|
+
- `BackendAuthInput`, `BackendProjectInput`, `BackendFileInput`,
|
|
373
|
+
`BackendUploadInput`, and `BackendCompileInput`: backend adapter request
|
|
374
|
+
shapes. They are accepted by `OverleafBackend` only and should not leak
|
|
375
|
+
private transport details.
|
|
376
|
+
- `BackendAccount`: redacted auth validation result suitable for status and
|
|
377
|
+
diagnostics.
|
|
378
|
+
- `RemoteFile`: metadata returned by the backend. Listings must not include full
|
|
379
|
+
file contents.
|
|
380
|
+
- `RemoteFile.path`: repository-relative file path using forward slashes in
|
|
381
|
+
internal state.
|
|
382
|
+
- `RemoteFile.kind`: whether the remote entry is a file or directory.
|
|
383
|
+
- `RemoteFile.remoteId`, `revision`, and `modifiedAt`: optional remote metadata
|
|
384
|
+
used only for efficient backend operations and conflict detection.
|
|
385
|
+
- `RemoteFile.contentHash`: deterministic digest when available. The backend may
|
|
386
|
+
omit it if content must be downloaded before hashing.
|
|
387
|
+
- `RemoteFile.binary`: whether the remote entry should be treated as binary.
|
|
388
|
+
- `LocalFileSnapshot.path`: repository-relative local file path using forward
|
|
389
|
+
slashes in internal state.
|
|
390
|
+
- `LocalFileSnapshot.exists`: whether the file exists at snapshot time.
|
|
391
|
+
- `LocalFileSnapshot.size`, `contentHash`, and `modifiedAt`: deterministic local
|
|
392
|
+
metadata used for sync planning.
|
|
393
|
+
- `LocalFileSnapshot.ignored`: whether the path is excluded by built-in or
|
|
394
|
+
project ignore rules.
|
|
395
|
+
- `SyncOperation.type`: planned action for a path before application.
|
|
396
|
+
- `SyncOperation.reason`: short redacted explanation for why the operation was
|
|
397
|
+
selected.
|
|
398
|
+
- `SyncConflict.reason`: stable conflict category for later conflict report
|
|
399
|
+
formatting.
|
|
400
|
+
- `SyncConflict.recommendation`: user-facing next step without file contents or
|
|
401
|
+
secrets.
|
|
402
|
+
- `SyncPlan.projectId`: project binding used for this plan.
|
|
403
|
+
- `SyncPlan.createdAt`: ISO timestamp when the plan was produced.
|
|
404
|
+
- `SyncPlan.dryRun`: when true, neither local files nor remote files may be
|
|
405
|
+
mutated.
|
|
406
|
+
- `SyncPlan.operations`: planned changes. Operations with type `conflict` or
|
|
407
|
+
`ignored` are informative and must not mutate either side.
|
|
408
|
+
- `SyncPlan.conflicts`: blocking conflicts. Any non-empty array pauses automatic
|
|
409
|
+
application.
|
|
410
|
+
- `SyncPlan.summary`: counts for user output and tests.
|
|
411
|
+
- `CompileLogEntry`: redacted compile message, optionally associated with a file
|
|
412
|
+
and line number.
|
|
413
|
+
- `CompileResult.status`: compile outcome. `fallback-success` means the PDF came
|
|
414
|
+
from a fast or draft fallback, not from a normal full compile.
|
|
415
|
+
- `CompileResult.projectId`: project binding used for the compile.
|
|
416
|
+
- `CompileResult.pdfBytes`: backend-returned artifact bytes before local write.
|
|
417
|
+
- `CompileResult.pdfPath`: local path after the PDF is written.
|
|
418
|
+
- `CompileResult.logs`: redacted compile log entries.
|
|
419
|
+
- `CompileResult.warnings`: redacted warnings that should not fail the command
|
|
420
|
+
by themselves.
|
|
421
|
+
- `CompileResult.elapsedMs`: measured compile flow duration.
|
|
422
|
+
- `CompileResult.fallbackUsed`: true when the fast or draft fallback path
|
|
423
|
+
produced the returned result.
|
|
424
|
+
- `CompileResult.error`: structured failure for failed compile outcomes.
|
|
425
|
+
- `OlcxError.name`: constant discriminator.
|
|
426
|
+
- `OlcxError.code`: stable error category.
|
|
427
|
+
- `OlcxError.message`: redacted user-facing failure message.
|
|
428
|
+
- `OlcxError.exitCode`: process exit code selected by command boundary. Numeric
|
|
429
|
+
values are reserved for the later CLI behavior contract.
|
|
430
|
+
- `OlcxError.hint`: optional actionable next step.
|
|
431
|
+
- `OlcxError.details`: structured diagnostic details. It must not contain raw
|
|
432
|
+
cookies, session values, passwords, or full private file contents.
|
|
433
|
+
- `OlcxError.cause`: original thrown value retained for internal debugging only.
|
|
434
|
+
- `Result<T>`: preferred workflow-level return shape for expected failures.
|
|
435
|
+
|
|
436
|
+
## Stable Versus Private Interfaces
|
|
437
|
+
|
|
438
|
+
Stable internal contracts for other modules are `ProjectConfig`, `ProjectAuth`,
|
|
439
|
+
`OverleafBackend`, `RemoteFile`, `LocalFileSnapshot`, `SyncPlan`,
|
|
440
|
+
`SyncOperation`, `SyncConflict`, `CompileResult`, `CompileLogEntry`,
|
|
441
|
+
`OlcxError`, `OlcxErrorCode`, and `Result<T>`.
|
|
442
|
+
|
|
443
|
+
Private implementation details include imported or adapted `olcli` code, raw
|
|
444
|
+
Overleaf HTTP routes, raw cookies, session parsing, backend retry internals,
|
|
445
|
+
HTML or CSRF parsing, and temporary protocol models.
|
|
446
|
+
|
|
447
|
+
No command, sync, compile, watch, diagnostics, or test module should import from
|
|
448
|
+
`src/backend/olcli/*` directly. Those modules depend on `OverleafBackend`.
|
|
449
|
+
|
|
450
|
+
## Command-To-Module Dependencies
|
|
451
|
+
|
|
452
|
+
| Command | Command Module | Allowed Dependencies | Backend Requirement |
|
|
453
|
+
| --- | --- | --- | --- |
|
|
454
|
+
| `auth` | `src/commands/auth.ts` | `config`, `auth`, optional `backend.validateAuth`, `diagnostics` redaction | Optional validation only |
|
|
455
|
+
| `init` | `src/commands/init.ts` | `config`, `config/ignoreRules`, VS Code config helper | None |
|
|
456
|
+
| `sync` | `src/commands/sync.ts` | `config`, `auth`, `backend`, `sync`, `diagnostics` | Required |
|
|
457
|
+
| `compile` | `src/commands/compile.ts` | `config`, `auth`, `backend`, `compile`, `diagnostics` | Required |
|
|
458
|
+
| `watch` | `src/commands/watch.ts` | `config`, `auth`, `watch`, `sync`, `compile`, `diagnostics` | Required through sync and compile |
|
|
459
|
+
| `status` | `src/commands/status.ts` | `config`, `auth`, sync state, `diagnostics` | Only if a later explicit remote check is requested |
|
|
460
|
+
| `doctor` | `src/commands/doctor.ts` | `config`, `auth`, `diagnostics`, backend capability checks | Must not require real Overleaf by default |
|
|
461
|
+
|
|
462
|
+
Commands convert workflow `Result<T>` values into stdout, stderr, and process
|
|
463
|
+
exit behavior. They must not invent alternate error shapes.
|
|
464
|
+
|
|
465
|
+
## Path Ownership
|
|
466
|
+
|
|
467
|
+
| Path | Owner | Contract |
|
|
468
|
+
| --- | --- | --- |
|
|
469
|
+
| `.olcx/config.json` | `src/config` | Shareable workflow config. May reveal project binding. Must not contain credentials. |
|
|
470
|
+
| `.olcx/auth.local.json` | `src/auth` | Local-only secret auth file. Must remain ignored. Must not contain passwords. |
|
|
471
|
+
| `.olcx/state/` | `src/sync` and `src/watch` | Local-only state directory for snapshots, conflicts, and pause state. Must remain ignored. |
|
|
472
|
+
| `.olcx/state/sync.json` | `src/sync` | Sync snapshot state. Local-only and ignored. |
|
|
473
|
+
| `.olcx/state/conflicts.json` | `src/sync` | Conflict report state. Local-only and ignored. |
|
|
474
|
+
| `.olcx/state/watch.json` | `src/watch` | Watch pause and queue metadata when persistence is needed. Local-only and ignored. |
|
|
475
|
+
| `build/overleaf/main.pdf` | `src/compile` | Default generated PDF output. Must remain ignored. |
|
|
476
|
+
| `.gitignore` | `src/config` ignore helper and `init` | Managed conservatively. Preserve user entries and ensure required local-only/generated paths stay ignored. |
|
|
477
|
+
| `.vscode/settings.json` | `init` VS Code helper | Generated or merged VS Code configuration. Preserve user content. |
|
|
478
|
+
| `.vscode/tasks.json` | `init` VS Code helper | Generated or merged VS Code tasks. Preserve user content and replace only olcx-managed task labels. |
|
|
479
|
+
|
|
480
|
+
## Ignore Rules Contract
|
|
481
|
+
|
|
482
|
+
Sync and watch share one deterministic ignore-rule implementation. They must
|
|
483
|
+
exclude:
|
|
484
|
+
|
|
485
|
+
- `.git/`
|
|
486
|
+
- `node_modules/`
|
|
487
|
+
- `.olcx/auth.local.json`
|
|
488
|
+
- `.olcx/*.local.json`
|
|
489
|
+
- `.olcx/*.secret.json`
|
|
490
|
+
- `.olcx/state/`
|
|
491
|
+
- `build/overleaf/`
|
|
492
|
+
- `*.aux`
|
|
493
|
+
- `*.bbl`
|
|
494
|
+
- `*.bcf`
|
|
495
|
+
- `*.blg`
|
|
496
|
+
- `*.fdb_latexmk`
|
|
497
|
+
- `*.fls`
|
|
498
|
+
- `*.log`
|
|
499
|
+
- `*.out`
|
|
500
|
+
- `*.run.xml`
|
|
501
|
+
- `*.synctex.gz`
|
|
502
|
+
- `*.toc`
|
|
503
|
+
- user-configured patterns from `ProjectConfig.sync.ignore`
|
|
504
|
+
|
|
505
|
+
Ignore handling must be path-normalized and deterministic across platforms.
|
|
506
|
+
Ignored files are never uploaded, downloaded, watched for automatic workflow
|
|
507
|
+
triggers, or included in conflict reports except as counted ignored entries.
|
|
508
|
+
|
|
509
|
+
## Error Model And Exit Categories
|
|
510
|
+
|
|
511
|
+
Workflow modules should return `Result<T>` for expected failures. Expected
|
|
512
|
+
failures include:
|
|
513
|
+
|
|
514
|
+
- user input errors;
|
|
515
|
+
- missing or invalid project config;
|
|
516
|
+
- missing or invalid project auth;
|
|
517
|
+
- backend auth failures;
|
|
518
|
+
- backend network failures;
|
|
519
|
+
- backend protocol failures;
|
|
520
|
+
- sync conflicts;
|
|
521
|
+
- unsafe sync operations;
|
|
522
|
+
- compile failures;
|
|
523
|
+
- compile timeouts;
|
|
524
|
+
- local I/O failures.
|
|
525
|
+
|
|
526
|
+
CLI commands convert `OlcxError.exitCode` to the process exit code and print a
|
|
527
|
+
redacted `message` plus an optional `hint`. Unexpected thrown errors are
|
|
528
|
+
converted at the command boundary into `INTERNAL_ERROR`.
|
|
529
|
+
|
|
530
|
+
Numeric exit-code mapping is intentionally deferred to task
|
|
531
|
+
`20260625-163246-549133`. Until that task finalizes numbers, modules must depend
|
|
532
|
+
on `OlcxErrorCode` categories rather than hard-coding incompatible numeric
|
|
533
|
+
meanings.
|
|
534
|
+
|
|
535
|
+
`OlcxError.details`, command output, logs, snapshots, test fixtures, and handoff
|
|
536
|
+
reports must not include raw cookies, session values, passwords, or full private
|
|
537
|
+
file contents.
|
|
538
|
+
|
|
539
|
+
## olcli MIT Attribution Boundary
|
|
540
|
+
|
|
541
|
+
MIT-derived code from `aloth/olcli` may live only under `src/backend/olcli/` or
|
|
542
|
+
an equivalent backend-private path. Copied or adapted files must preserve the
|
|
543
|
+
original MIT attribution and notices required by their source.
|
|
544
|
+
|
|
545
|
+
Users install and run `olcx`; they do not install `olcli` separately at runtime.
|
|
546
|
+
Only backend adapter modules may call `olcli`-derived private APIs or private
|
|
547
|
+
Overleaf endpoints. All other modules depend on `OverleafBackend`.
|
|
548
|
+
|
|
549
|
+
The backend adapter translates `olcli` or private Overleaf failures into
|
|
550
|
+
redacted `OlcxError` values. Upper layers must not branch on private Overleaf
|
|
551
|
+
routes, raw HTML markers, CSRF details, or `olcli` internal classes.
|
|
552
|
+
|
|
553
|
+
## Fake Backend And Testing Boundaries
|
|
554
|
+
|
|
555
|
+
`src/testing/fakeBackend.ts` should implement `OverleafBackend`
|
|
556
|
+
deterministically. Unit and integration tests should use fake backend instances
|
|
557
|
+
and temporary paper repositories rather than real Overleaf.
|
|
558
|
+
|
|
559
|
+
Fixtures must not contain real paper content, credentials, cookies, session
|
|
560
|
+
values, passwords, account data, or private project IDs. Placeholder values such
|
|
561
|
+
as `<overleaf-project-id>` and `<redacted-session-cookie>` are acceptable.
|
|
562
|
+
|
|
563
|
+
Real Overleaf E2E tests are gated by local-only environment variables and belong
|
|
564
|
+
to task `20260625-160946-910101`. Normal `npm test` runs must not require
|
|
565
|
+
network access, a real Overleaf account, local LaTeX, Playwright, or browser
|
|
566
|
+
automation.
|
|
567
|
+
|
|
568
|
+
Compile tests should use fake PDF bytes and verify write paths. Sync tests should
|
|
569
|
+
verify snapshots, plans, conflict detection, and ignore filtering without
|
|
570
|
+
uploading real files.
|
|
571
|
+
|
|
572
|
+
## Security Constraints
|
|
573
|
+
|
|
574
|
+
- `.olcx/auth.local.json`, `.olcx/*.local.json`, `.olcx/*.secret.json`,
|
|
575
|
+
`.env.e2e.local`, and local state under `.olcx/state/` must remain ignored.
|
|
576
|
+
- Redaction must happen before secret-like values reach command output, logs,
|
|
577
|
+
errors, test snapshots, docs, or QuickDev handoff reports.
|
|
578
|
+
- Overleaf passwords must not be stored.
|
|
579
|
+
- Raw cookies and raw session values must not be printed.
|
|
580
|
+
- Real project IDs, account data, private paper content, and real compile logs
|
|
581
|
+
must not be placed in fixtures or docs.
|
|
582
|
+
- Conflict reports include paths, hashes, sizes, timestamps, conflict reasons,
|
|
583
|
+
and recommendations. They must not include full file contents.
|
|
584
|
+
- `ProjectConfig.projectId` is shareable config, but users should treat it as
|
|
585
|
+
potentially sensitive when a paper repository is public.
|
|
586
|
+
|
|
587
|
+
## Open Follow-Up Contracts
|
|
588
|
+
|
|
589
|
+
- CLI output, stdout and stderr rules, non-interactive behavior, redaction text,
|
|
590
|
+
and numeric exit-code mapping belong to task `20260625-163246-549133`.
|
|
591
|
+
- Sync state-machine details, snapshot persistence format, delete semantics, and
|
|
592
|
+
conflict report format belong to task `20260625-163308-046461`.
|
|
593
|
+
- Exact `olcli` import layout, source file selection, and notice updates belong
|
|
594
|
+
to task `20260625-160751-353900`.
|
|
595
|
+
- Backend adapter implementation details and fake backend behavior belong to task
|
|
596
|
+
`20260625-160853-429297`.
|
|
597
|
+
- Config/auth schemas, project root discovery, redaction helpers, and `.gitignore`
|
|
598
|
+
update behavior belong to task `20260625-160804-867992`.
|
|
599
|
+
- Default init VS Code merge behavior belongs to task `20260625-160819-417512`.
|
|
600
|
+
- Remote compile polling, PDF write behavior, and fast fallback implementation
|
|
601
|
+
belong to tasks `20260625-160925-146032` and `20260625-165248-545991`.
|
|
602
|
+
- Real Overleaf E2E gating and local-only secret loading belong to task
|
|
603
|
+
`20260625-160946-910101`.
|
package/docs/auth.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Auth
|
|
2
|
+
|
|
3
|
+
`olcx auth` stores project-local Overleaf authorization for the current paper
|
|
4
|
+
repository. It must not store Overleaf passwords.
|
|
5
|
+
|
|
6
|
+
## Interactive Auth
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
olcx auth
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The command prompts for a copied Overleaf session cookie and writes:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
.olcx/auth.local.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The auth file is ignored by Git and should never be pasted into issues, docs,
|
|
19
|
+
tests, or handoff files.
|
|
20
|
+
|
|
21
|
+
## Headless Auth
|
|
22
|
+
|
|
23
|
+
Linux/macOS:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
export OLCX_OVERLEAF_SESSION='<copied-session-cookie>'
|
|
27
|
+
olcx auth --from-env OLCX_OVERLEAF_SESSION
|
|
28
|
+
unset OLCX_OVERLEAF_SESSION
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Windows PowerShell:
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
$env:OLCX_OVERLEAF_SESSION = '<copied-session-cookie>'
|
|
35
|
+
olcx auth --from-env OLCX_OVERLEAF_SESSION
|
|
36
|
+
Remove-Item Env:OLCX_OVERLEAF_SESSION
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
One-shot paste:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
olcx auth --cookie '<copied-session-cookie>'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Use `OLCX_NON_INTERACTIVE=1` or `CI=true` when prompts are not allowed.
|
|
46
|
+
Prefer `--from-env` for shared terminals and shell history. Use `--account
|
|
47
|
+
<label>` only for a local label shown by `olcx status`; do not put private
|
|
48
|
+
account data in public logs.
|
|
49
|
+
|
|
50
|
+
## Non-Interactive Mode
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
OLCX_NON_INTERACTIVE=1 olcx auth --from-env OLCX_OVERLEAF_SESSION
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`OLCX_NON_INTERACTIVE=1` and `CI=true` make auth fail fast when no source is
|
|
57
|
+
provided.
|
|
58
|
+
|
|
59
|
+
## Safety Rules
|
|
60
|
+
|
|
61
|
+
- Keep `.olcx/auth.local.json` ignored.
|
|
62
|
+
- Keep `*.local.json` and `*.secret.json` ignored.
|
|
63
|
+
- Use placeholders in examples.
|
|
64
|
+
- Do not report cookies, session values, account data, or private project IDs.
|
|
65
|
+
- Re-run `olcx auth` if Overleaf rejects the stored session.
|