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.

Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +25 -0
  3. package/README.md +217 -0
  4. package/assets/olcx-mark.svg +22 -0
  5. package/dist/auth/projectAuth.d.ts +19 -0
  6. package/dist/auth/projectAuth.js +163 -0
  7. package/dist/auth/projectAuth.js.map +1 -0
  8. package/dist/auth/redact.d.ts +3 -0
  9. package/dist/auth/redact.js +7 -0
  10. package/dist/auth/redact.js.map +1 -0
  11. package/dist/auth/types.d.ts +10 -0
  12. package/dist/auth/types.js +4 -0
  13. package/dist/auth/types.js.map +1 -0
  14. package/dist/backend/index.d.ts +6 -0
  15. package/dist/backend/index.js +2 -0
  16. package/dist/backend/index.js.map +1 -0
  17. package/dist/backend/olcli/client.d.ts +329 -0
  18. package/dist/backend/olcli/client.js +1757 -0
  19. package/dist/backend/olcli/client.js.map +1 -0
  20. package/dist/backend/olcli/index.d.ts +2 -0
  21. package/dist/backend/olcli/index.js +2 -0
  22. package/dist/backend/olcli/index.js.map +1 -0
  23. package/dist/backend/overleafBackend.d.ts +41 -0
  24. package/dist/backend/overleafBackend.js +200 -0
  25. package/dist/backend/overleafBackend.js.map +1 -0
  26. package/dist/backend/types.d.ts +73 -0
  27. package/dist/backend/types.js +2 -0
  28. package/dist/backend/types.js.map +1 -0
  29. package/dist/cli-behavior.d.ts +14 -0
  30. package/dist/cli-behavior.js +59 -0
  31. package/dist/cli-behavior.js.map +1 -0
  32. package/dist/cli.d.ts +30 -0
  33. package/dist/cli.js +441 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/commands/auth.d.ts +21 -0
  36. package/dist/commands/auth.js +104 -0
  37. package/dist/commands/auth.js.map +1 -0
  38. package/dist/commands/compile.d.ts +7 -0
  39. package/dist/commands/compile.js +73 -0
  40. package/dist/commands/compile.js.map +1 -0
  41. package/dist/commands/doctor.d.ts +11 -0
  42. package/dist/commands/doctor.js +9 -0
  43. package/dist/commands/doctor.js.map +1 -0
  44. package/dist/commands/endpoint.d.ts +23 -0
  45. package/dist/commands/endpoint.js +69 -0
  46. package/dist/commands/endpoint.js.map +1 -0
  47. package/dist/commands/init.d.ts +14 -0
  48. package/dist/commands/init.js +48 -0
  49. package/dist/commands/init.js.map +1 -0
  50. package/dist/commands/status.d.ts +4 -0
  51. package/dist/commands/status.js +5 -0
  52. package/dist/commands/status.js.map +1 -0
  53. package/dist/commands/sync.d.ts +26 -0
  54. package/dist/commands/sync.js +139 -0
  55. package/dist/commands/sync.js.map +1 -0
  56. package/dist/commands/watch.d.ts +28 -0
  57. package/dist/commands/watch.js +124 -0
  58. package/dist/commands/watch.js.map +1 -0
  59. package/dist/compile/compileFlow.d.ts +32 -0
  60. package/dist/compile/compileFlow.js +290 -0
  61. package/dist/compile/compileFlow.js.map +1 -0
  62. package/dist/compile/pdfOutput.d.ts +12 -0
  63. package/dist/compile/pdfOutput.js +64 -0
  64. package/dist/compile/pdfOutput.js.map +1 -0
  65. package/dist/config/ignoreRules.d.ts +5 -0
  66. package/dist/config/ignoreRules.js +53 -0
  67. package/dist/config/ignoreRules.js.map +1 -0
  68. package/dist/config/overleafProject.d.ts +9 -0
  69. package/dist/config/overleafProject.js +61 -0
  70. package/dist/config/overleafProject.js.map +1 -0
  71. package/dist/config/projectConfig.d.ts +6 -0
  72. package/dist/config/projectConfig.js +180 -0
  73. package/dist/config/projectConfig.js.map +1 -0
  74. package/dist/config/projectRoot.d.ts +1 -0
  75. package/dist/config/projectRoot.js +36 -0
  76. package/dist/config/projectRoot.js.map +1 -0
  77. package/dist/config/types.d.ts +50 -0
  78. package/dist/config/types.js +34 -0
  79. package/dist/config/types.js.map +1 -0
  80. package/dist/config/vscode.d.ts +10 -0
  81. package/dist/config/vscode.js +134 -0
  82. package/dist/config/vscode.js.map +1 -0
  83. package/dist/diagnostics/doctor.d.ts +8 -0
  84. package/dist/diagnostics/doctor.js +209 -0
  85. package/dist/diagnostics/doctor.js.map +1 -0
  86. package/dist/diagnostics/status.d.ts +6 -0
  87. package/dist/diagnostics/status.js +110 -0
  88. package/dist/diagnostics/status.js.map +1 -0
  89. package/dist/diagnostics/types.d.ts +33 -0
  90. package/dist/diagnostics/types.js +2 -0
  91. package/dist/diagnostics/types.js.map +1 -0
  92. package/dist/endpoint/overleafEndpoint.d.ts +36 -0
  93. package/dist/endpoint/overleafEndpoint.js +105 -0
  94. package/dist/endpoint/overleafEndpoint.js.map +1 -0
  95. package/dist/errors.d.ts +32 -0
  96. package/dist/errors.js +53 -0
  97. package/dist/errors.js.map +1 -0
  98. package/dist/sync/apply.d.ts +14 -0
  99. package/dist/sync/apply.js +92 -0
  100. package/dist/sync/apply.js.map +1 -0
  101. package/dist/sync/conflicts.d.ts +7 -0
  102. package/dist/sync/conflicts.js +59 -0
  103. package/dist/sync/conflicts.js.map +1 -0
  104. package/dist/sync/ignore.d.ts +5 -0
  105. package/dist/sync/ignore.js +74 -0
  106. package/dist/sync/ignore.js.map +1 -0
  107. package/dist/sync/plan.d.ts +3 -0
  108. package/dist/sync/plan.js +197 -0
  109. package/dist/sync/plan.js.map +1 -0
  110. package/dist/sync/snapshot.d.ts +13 -0
  111. package/dist/sync/snapshot.js +82 -0
  112. package/dist/sync/snapshot.js.map +1 -0
  113. package/dist/sync/state.d.ts +16 -0
  114. package/dist/sync/state.js +214 -0
  115. package/dist/sync/state.js.map +1 -0
  116. package/dist/sync/types.d.ts +113 -0
  117. package/dist/sync/types.js +4 -0
  118. package/dist/sync/types.js.map +1 -0
  119. package/dist/testing/fakeBackend.d.ts +27 -0
  120. package/dist/testing/fakeBackend.js +213 -0
  121. package/dist/testing/fakeBackend.js.map +1 -0
  122. package/dist/watch/queue.d.ts +2 -0
  123. package/dist/watch/queue.js +91 -0
  124. package/dist/watch/queue.js.map +1 -0
  125. package/dist/watch/types.d.ts +52 -0
  126. package/dist/watch/types.js +2 -0
  127. package/dist/watch/types.js.map +1 -0
  128. package/dist/watch/watcher.d.ts +6 -0
  129. package/dist/watch/watcher.js +58 -0
  130. package/dist/watch/watcher.js.map +1 -0
  131. package/dist/watch/workflow.d.ts +30 -0
  132. package/dist/watch/workflow.js +62 -0
  133. package/dist/watch/workflow.js.map +1 -0
  134. package/docs/architecture.md +603 -0
  135. package/docs/auth.md +65 -0
  136. package/docs/cli-behavior.md +95 -0
  137. package/docs/compile.md +51 -0
  138. package/docs/design.md +82 -0
  139. package/docs/endpoint.md +84 -0
  140. package/docs/npm-packaging.md +148 -0
  141. package/docs/quickdev-queue-audit.md +193 -0
  142. package/docs/release-gates.md +119 -0
  143. package/docs/release-notes-v1.md +97 -0
  144. package/docs/security.md +61 -0
  145. package/docs/sync-state.md +305 -0
  146. package/docs/sync.md +50 -0
  147. package/docs/troubleshooting.md +124 -0
  148. package/docs/usage.md +184 -0
  149. package/examples/minimal-paper/.olcx/auth.local.example.json +7 -0
  150. package/examples/minimal-paper/.olcx/config.json +23 -0
  151. package/examples/minimal-paper/README.md +88 -0
  152. package/examples/minimal-paper/main.tex +23 -0
  153. package/package.json +66 -0
  154. package/src/backend/olcli/LICENSE +21 -0
  155. 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.