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,180 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, join, win32 } from "node:path";
|
|
3
|
+
import { createOlcxError } from "../errors.js";
|
|
4
|
+
import { DEFAULT_OVERLEAF_BASE_URL, MAX_FAST_FALLBACK_ATTEMPTS, OLCX_DIR, PROJECT_CONFIG_FILENAME, } from "./types.js";
|
|
5
|
+
const FORBIDDEN_SECRET_KEYS = new Set(["password", "sessioncookie", "cookie", "token", "auth", "authorization", "csrf"]);
|
|
6
|
+
export function getProjectConfigPath(projectRoot) {
|
|
7
|
+
return join(projectRoot, OLCX_DIR, PROJECT_CONFIG_FILENAME);
|
|
8
|
+
}
|
|
9
|
+
export async function readProjectConfig(projectRoot) {
|
|
10
|
+
const path = getProjectConfigPath(projectRoot);
|
|
11
|
+
let raw;
|
|
12
|
+
try {
|
|
13
|
+
raw = await readFile(path, "utf8");
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (isNodeError(error, "ENOENT")) {
|
|
17
|
+
throw createOlcxError({
|
|
18
|
+
code: "PROJECT_CONFIG_NOT_FOUND",
|
|
19
|
+
message: "Project config was not found.",
|
|
20
|
+
hint: "Run olcx init for this paper repository before using project commands.",
|
|
21
|
+
details: { path: ".olcx/config.json" },
|
|
22
|
+
cause: error,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
return validateProjectConfig(JSON.parse(raw));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw createOlcxError({
|
|
32
|
+
code: "PROJECT_CONFIG_INVALID",
|
|
33
|
+
message: "Project config is invalid.",
|
|
34
|
+
hint: "Fix .olcx/config.json or regenerate it with olcx init.",
|
|
35
|
+
details: {
|
|
36
|
+
path: ".olcx/config.json",
|
|
37
|
+
reason: error instanceof Error ? error.message : "Invalid JSON or schema.",
|
|
38
|
+
},
|
|
39
|
+
cause: error,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export async function writeProjectConfig(projectRoot, config) {
|
|
44
|
+
const validated = validateProjectConfig(config);
|
|
45
|
+
await mkdir(join(projectRoot, OLCX_DIR), { recursive: true });
|
|
46
|
+
await writeFile(getProjectConfigPath(projectRoot), `${JSON.stringify(validated, null, 2)}\n`, "utf8");
|
|
47
|
+
}
|
|
48
|
+
export function validateProjectConfig(value) {
|
|
49
|
+
assertRecord(value, "config");
|
|
50
|
+
assertNoForbiddenSecretKeys(value, "config");
|
|
51
|
+
if (value.schemaVersion !== 1) {
|
|
52
|
+
throw new Error("schemaVersion must be 1");
|
|
53
|
+
}
|
|
54
|
+
const projectId = requireNonEmptyString(value.projectId, "projectId");
|
|
55
|
+
const overleaf = value.overleaf === undefined ? undefined : requireRecord(value.overleaf, "overleaf");
|
|
56
|
+
const overleafBaseUrl = overleaf === undefined
|
|
57
|
+
? DEFAULT_OVERLEAF_BASE_URL
|
|
58
|
+
: requireOverleafBaseUrl(overleaf.baseUrl, "overleaf.baseUrl");
|
|
59
|
+
const rootDocument = requireSafeRelativePath(value.rootDocument, "rootDocument");
|
|
60
|
+
const pdfPath = requireSafeRelativePath(value.pdfPath, "pdfPath");
|
|
61
|
+
const sync = requireRecord(value.sync, "sync");
|
|
62
|
+
const compile = requireRecord(value.compile, "compile");
|
|
63
|
+
const fastFallback = requireRecord(compile.fastFallback, "compile.fastFallback");
|
|
64
|
+
if (sync.mode !== "bidirectional") {
|
|
65
|
+
throw new Error('sync.mode must be "bidirectional"');
|
|
66
|
+
}
|
|
67
|
+
if (sync.conflictPolicy !== "pause") {
|
|
68
|
+
throw new Error('sync.conflictPolicy must be "pause"');
|
|
69
|
+
}
|
|
70
|
+
if (!Array.isArray(sync.ignore)) {
|
|
71
|
+
throw new Error("sync.ignore must be an array");
|
|
72
|
+
}
|
|
73
|
+
const ignore = sync.ignore.map((entry, index) => requireNonEmptyString(entry, `sync.ignore[${index}]`));
|
|
74
|
+
const timeoutMs = requirePositiveInteger(compile.timeoutMs, "compile.timeoutMs");
|
|
75
|
+
const fastFallbackTimeoutMs = requirePositiveInteger(fastFallback.timeoutMs, "compile.fastFallback.timeoutMs");
|
|
76
|
+
const attempts = requireIntegerInRange(fastFallback.attempts, "compile.fastFallback.attempts", 0, MAX_FAST_FALLBACK_ATTEMPTS);
|
|
77
|
+
if (typeof fastFallback.enabled !== "boolean") {
|
|
78
|
+
throw new Error("compile.fastFallback.enabled must be a boolean");
|
|
79
|
+
}
|
|
80
|
+
const config = {
|
|
81
|
+
schemaVersion: 1,
|
|
82
|
+
projectId,
|
|
83
|
+
overleaf: {
|
|
84
|
+
baseUrl: overleafBaseUrl,
|
|
85
|
+
},
|
|
86
|
+
rootDocument,
|
|
87
|
+
pdfPath,
|
|
88
|
+
sync: {
|
|
89
|
+
mode: "bidirectional",
|
|
90
|
+
conflictPolicy: "pause",
|
|
91
|
+
ignore,
|
|
92
|
+
},
|
|
93
|
+
compile: {
|
|
94
|
+
timeoutMs,
|
|
95
|
+
fastFallback: {
|
|
96
|
+
enabled: fastFallback.enabled,
|
|
97
|
+
attempts,
|
|
98
|
+
timeoutMs: fastFallbackTimeoutMs,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
if (value.projectUrl !== undefined) {
|
|
103
|
+
config.projectUrl = requireNonEmptyString(value.projectUrl, "projectUrl");
|
|
104
|
+
}
|
|
105
|
+
return config;
|
|
106
|
+
}
|
|
107
|
+
export function summarizeProjectConfig(config) {
|
|
108
|
+
return {
|
|
109
|
+
schemaVersion: config.schemaVersion,
|
|
110
|
+
hasProjectId: config.projectId.trim().length > 0,
|
|
111
|
+
hasProjectUrl: config.projectUrl !== undefined,
|
|
112
|
+
overleaf: config.overleaf,
|
|
113
|
+
rootDocument: config.rootDocument,
|
|
114
|
+
pdfPath: config.pdfPath,
|
|
115
|
+
sync: config.sync,
|
|
116
|
+
compile: config.compile,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function assertRecord(value, field) {
|
|
120
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
121
|
+
throw new Error(`${field} must be an object`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function requireRecord(value, field) {
|
|
125
|
+
assertRecord(value, field);
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
function requireNonEmptyString(value, field) {
|
|
129
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
130
|
+
throw new Error(`${field} must be a non-empty string`);
|
|
131
|
+
}
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
function requireOverleafBaseUrl(value, field) {
|
|
135
|
+
const baseUrl = requireNonEmptyString(value, field);
|
|
136
|
+
if (baseUrl !== "https://www.overleaf.com" && baseUrl !== "https://cn.overleaf.com") {
|
|
137
|
+
throw new Error(`${field} must be https://www.overleaf.com or https://cn.overleaf.com`);
|
|
138
|
+
}
|
|
139
|
+
return baseUrl;
|
|
140
|
+
}
|
|
141
|
+
function requireSafeRelativePath(value, field) {
|
|
142
|
+
const path = requireNonEmptyString(value, field);
|
|
143
|
+
const normalized = path.replace(/\\/g, "/");
|
|
144
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
145
|
+
if (isAbsolute(path) || win32.isAbsolute(path) || segments.includes("..")) {
|
|
146
|
+
throw new Error(`${field} must be a safe relative path`);
|
|
147
|
+
}
|
|
148
|
+
return normalized;
|
|
149
|
+
}
|
|
150
|
+
function requirePositiveInteger(value, field) {
|
|
151
|
+
if (!Number.isInteger(value) || typeof value !== "number" || value <= 0) {
|
|
152
|
+
throw new Error(`${field} must be a positive integer`);
|
|
153
|
+
}
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
156
|
+
function requireIntegerInRange(value, field, min, max) {
|
|
157
|
+
if (!Number.isInteger(value) || typeof value !== "number" || value < min || value > max) {
|
|
158
|
+
throw new Error(`${field} must be an integer from ${min} to ${max}`);
|
|
159
|
+
}
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
function assertNoForbiddenSecretKeys(value, field) {
|
|
163
|
+
if (Array.isArray(value)) {
|
|
164
|
+
value.forEach((entry, index) => assertNoForbiddenSecretKeys(entry, `${field}[${index}]`));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (!value || typeof value !== "object") {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
171
|
+
if (FORBIDDEN_SECRET_KEYS.has(key.toLowerCase())) {
|
|
172
|
+
throw new Error(`${field}.${key} is not allowed in project config`);
|
|
173
|
+
}
|
|
174
|
+
assertNoForbiddenSecretKeys(entry, `${field}.${key}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function isNodeError(error, code) {
|
|
178
|
+
return typeof error === "object" && error !== null && error.code === code;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=projectConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectConfig.js","sourceRoot":"","sources":["../../src/config/projectConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function findProjectRoot(startDir: string): Promise<string>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, parse, resolve } from "node:path";
|
|
3
|
+
import { PROJECT_CONFIG_PATH } from "./types.js";
|
|
4
|
+
export async function findProjectRoot(startDir) {
|
|
5
|
+
const original = resolve(startDir);
|
|
6
|
+
let current = original;
|
|
7
|
+
const root = parse(current).root;
|
|
8
|
+
while (true) {
|
|
9
|
+
if (await exists(join(current, PROJECT_CONFIG_PATH))) {
|
|
10
|
+
return current;
|
|
11
|
+
}
|
|
12
|
+
if (await exists(join(current, ".git"))) {
|
|
13
|
+
return current;
|
|
14
|
+
}
|
|
15
|
+
if (await exists(join(current, "package.json"))) {
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
if (current === root) {
|
|
19
|
+
return original;
|
|
20
|
+
}
|
|
21
|
+
current = dirname(current);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function exists(path) {
|
|
25
|
+
try {
|
|
26
|
+
await stat(path);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (typeof error === "object" && error !== null && error.code === "ENOENT") {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=projectRoot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectRoot.js","sourceRoot":"","sources":["../../src/config/projectRoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,OAAO,GAAG,QAAQ,CAAC;IACvB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;IAEjC,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC;YACrD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;YACxC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAChD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtG,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export declare const OLCX_DIR: ".olcx";
|
|
2
|
+
export declare const PROJECT_CONFIG_FILENAME: "config.json";
|
|
3
|
+
export declare const PROJECT_CONFIG_PATH: ".olcx/config.json";
|
|
4
|
+
export declare const MAX_FAST_FALLBACK_ATTEMPTS: 3;
|
|
5
|
+
export type OverleafBaseUrl = "https://www.overleaf.com" | "https://cn.overleaf.com";
|
|
6
|
+
export declare const DEFAULT_OVERLEAF_BASE_URL: OverleafBaseUrl;
|
|
7
|
+
export interface ProjectConfig {
|
|
8
|
+
schemaVersion: 1;
|
|
9
|
+
projectId: string;
|
|
10
|
+
projectUrl?: string;
|
|
11
|
+
overleaf: {
|
|
12
|
+
baseUrl: OverleafBaseUrl;
|
|
13
|
+
};
|
|
14
|
+
rootDocument: string;
|
|
15
|
+
pdfPath: string;
|
|
16
|
+
sync: {
|
|
17
|
+
mode: "bidirectional";
|
|
18
|
+
conflictPolicy: "pause";
|
|
19
|
+
ignore: string[];
|
|
20
|
+
};
|
|
21
|
+
compile: {
|
|
22
|
+
timeoutMs: number;
|
|
23
|
+
fastFallback: {
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
attempts: number;
|
|
26
|
+
timeoutMs: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface CreateDefaultProjectConfigInput {
|
|
31
|
+
projectId: string;
|
|
32
|
+
projectUrl?: string;
|
|
33
|
+
overleaf?: {
|
|
34
|
+
baseUrl?: OverleafBaseUrl;
|
|
35
|
+
};
|
|
36
|
+
rootDocument?: string;
|
|
37
|
+
pdfPath?: string;
|
|
38
|
+
sync?: {
|
|
39
|
+
ignore?: string[];
|
|
40
|
+
};
|
|
41
|
+
compile?: {
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
fastFallback?: {
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
attempts?: number;
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export declare function createDefaultProjectConfig(input: CreateDefaultProjectConfigInput): ProjectConfig;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const OLCX_DIR = ".olcx";
|
|
2
|
+
export const PROJECT_CONFIG_FILENAME = "config.json";
|
|
3
|
+
export const PROJECT_CONFIG_PATH = `${OLCX_DIR}/${PROJECT_CONFIG_FILENAME}`;
|
|
4
|
+
export const MAX_FAST_FALLBACK_ATTEMPTS = 3;
|
|
5
|
+
export const DEFAULT_OVERLEAF_BASE_URL = "https://www.overleaf.com";
|
|
6
|
+
export function createDefaultProjectConfig(input) {
|
|
7
|
+
const config = {
|
|
8
|
+
schemaVersion: 1,
|
|
9
|
+
projectId: input.projectId,
|
|
10
|
+
overleaf: {
|
|
11
|
+
baseUrl: input.overleaf?.baseUrl ?? DEFAULT_OVERLEAF_BASE_URL,
|
|
12
|
+
},
|
|
13
|
+
rootDocument: input.rootDocument ?? "main.tex",
|
|
14
|
+
pdfPath: input.pdfPath ?? "build/overleaf/main.pdf",
|
|
15
|
+
sync: {
|
|
16
|
+
mode: "bidirectional",
|
|
17
|
+
conflictPolicy: "pause",
|
|
18
|
+
ignore: input.sync?.ignore ?? [],
|
|
19
|
+
},
|
|
20
|
+
compile: {
|
|
21
|
+
timeoutMs: input.compile?.timeoutMs ?? 120000,
|
|
22
|
+
fastFallback: {
|
|
23
|
+
enabled: input.compile?.fastFallback?.enabled ?? true,
|
|
24
|
+
attempts: input.compile?.fastFallback?.attempts ?? 1,
|
|
25
|
+
timeoutMs: input.compile?.fastFallback?.timeoutMs ?? 30000,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
if (input.projectUrl !== undefined) {
|
|
30
|
+
config.projectUrl = input.projectUrl;
|
|
31
|
+
}
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAgB,CAAC;AACzC,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAsB,CAAC;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,QAAQ,IAAI,uBAAuB,EAAW,CAAC;AACrF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAU,CAAC;AAErD,MAAM,CAAC,MAAM,yBAAyB,GAAoB,0BAA0B,CAAC;AA+CrF,MAAM,UAAU,0BAA0B,CAAC,KAAsC;IAC/E,MAAM,MAAM,GAAkB;QAC5B,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE;YACR,OAAO,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,IAAI,yBAAyB;SAC9D;QACD,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,UAAU;QAC9C,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,yBAAyB;QACnD,IAAI,EAAE;YACJ,IAAI,EAAE,eAAe;YACrB,cAAc,EAAE,OAAO;YACvB,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE;SACjC;QACD,OAAO,EAAE;YACP,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,IAAI,MAAM;YAC7C,YAAY,EAAE;gBACZ,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,IAAI,IAAI;gBACrD,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,IAAI,CAAC;gBACpD,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,IAAI,KAAK;aAC3D;SACF;KACF,CAAC;IAEF,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACvC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface VsCodeConfigInput {
|
|
2
|
+
pdfPath: string;
|
|
3
|
+
rootDocument: string;
|
|
4
|
+
}
|
|
5
|
+
export interface VsCodeConfigResult {
|
|
6
|
+
changed: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function mergeVsCodeSettings(existing: unknown, input: VsCodeConfigInput): Record<string, unknown>;
|
|
9
|
+
export declare function mergeVsCodeTasks(existing: unknown): Record<string, unknown>;
|
|
10
|
+
export declare function ensureVsCodeConfig(projectRoot: string, input: VsCodeConfigInput): Promise<VsCodeConfigResult>;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createOlcxError } from "../errors.js";
|
|
4
|
+
const SETTINGS_FILENAME = "settings.json";
|
|
5
|
+
const TASKS_FILENAME = "tasks.json";
|
|
6
|
+
const OLCX_MANAGED_TASKS = [
|
|
7
|
+
{ label: "olcx: status", args: ["status"] },
|
|
8
|
+
{ label: "olcx: doctor", args: ["doctor"] },
|
|
9
|
+
{ label: "olcx: sync dry-run", args: ["sync", "--dry-run"] },
|
|
10
|
+
{ label: "olcx: sync apply", args: ["sync"] },
|
|
11
|
+
{ label: "olcx: compile", args: ["compile"] },
|
|
12
|
+
{ label: "olcx: watch", args: ["watch"] },
|
|
13
|
+
{ label: "olcx: endpoint status", args: ["endpoint", "status"] },
|
|
14
|
+
{ label: "olcx: endpoint test", args: ["endpoint", "test"] },
|
|
15
|
+
];
|
|
16
|
+
const OLCX_MANAGED_TASK_LABELS = new Set(OLCX_MANAGED_TASKS.map((task) => task.label));
|
|
17
|
+
export function mergeVsCodeSettings(existing, input) {
|
|
18
|
+
assertRecord(existing, ".vscode/settings.json");
|
|
19
|
+
return {
|
|
20
|
+
...existing,
|
|
21
|
+
"olcx.pdfPath": input.pdfPath,
|
|
22
|
+
"olcx.rootDocument": input.rootDocument,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function mergeVsCodeTasks(existing) {
|
|
26
|
+
assertRecord(existing, ".vscode/tasks.json");
|
|
27
|
+
const tasks = existing.tasks;
|
|
28
|
+
if (tasks !== undefined && !Array.isArray(tasks)) {
|
|
29
|
+
throw createOlcxError({
|
|
30
|
+
code: "PROJECT_CONFIG_INVALID",
|
|
31
|
+
message: ".vscode/tasks.json is invalid.",
|
|
32
|
+
hint: "Make tasks an array before running olcx init again.",
|
|
33
|
+
details: { path: ".vscode/tasks.json", reason: "tasks must be an array" },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
...existing,
|
|
38
|
+
version: "2.0.0",
|
|
39
|
+
tasks: [...(tasks ?? []).filter((task) => !isOlcxManagedTask(task)), ...OLCX_MANAGED_TASKS.map(createOlcxTask)],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export async function ensureVsCodeConfig(projectRoot, input) {
|
|
43
|
+
const vscodeDir = join(projectRoot, ".vscode");
|
|
44
|
+
await mkdir(vscodeDir, { recursive: true });
|
|
45
|
+
const settings = await prepareMergedJson(join(vscodeDir, SETTINGS_FILENAME), ".vscode/settings.json", (existing) => mergeVsCodeSettings(existing, input));
|
|
46
|
+
const tasks = await prepareMergedJson(join(vscodeDir, TASKS_FILENAME), ".vscode/tasks.json", mergeVsCodeTasks);
|
|
47
|
+
await writePreparedJson(settings);
|
|
48
|
+
await writePreparedJson(tasks);
|
|
49
|
+
return { changed: settings.changed || tasks.changed };
|
|
50
|
+
}
|
|
51
|
+
async function prepareMergedJson(path, displayPath, merge) {
|
|
52
|
+
const existing = await readJsonFile(path, displayPath);
|
|
53
|
+
const merged = merge(existing.value);
|
|
54
|
+
const nextContent = `${JSON.stringify(merged, null, 2)}\n`;
|
|
55
|
+
return {
|
|
56
|
+
path,
|
|
57
|
+
content: nextContent,
|
|
58
|
+
changed: existing.content !== nextContent,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function writePreparedJson(prepared) {
|
|
62
|
+
if (prepared.changed) {
|
|
63
|
+
await writeFile(prepared.path, prepared.content, "utf8");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function readJsonFile(path, displayPath) {
|
|
67
|
+
let content;
|
|
68
|
+
try {
|
|
69
|
+
content = await readFile(path, "utf8");
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (isNodeError(error, "ENOENT")) {
|
|
73
|
+
return { value: {} };
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
return { value: JSON.parse(content), content };
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
throw createOlcxError({
|
|
82
|
+
code: "PROJECT_CONFIG_INVALID",
|
|
83
|
+
message: `${displayPath} contains invalid JSON.`,
|
|
84
|
+
hint: `Fix ${displayPath} before running olcx init again.`,
|
|
85
|
+
details: { path: displayPath, reason: error instanceof Error ? error.message : "Invalid JSON" },
|
|
86
|
+
cause: error,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function createOlcxTask(spec) {
|
|
91
|
+
const task = {
|
|
92
|
+
label: spec.label,
|
|
93
|
+
type: "shell",
|
|
94
|
+
command: "olcx",
|
|
95
|
+
args: [...spec.args],
|
|
96
|
+
problemMatcher: [],
|
|
97
|
+
};
|
|
98
|
+
if (spec.label === "olcx: compile") {
|
|
99
|
+
task.group = "build";
|
|
100
|
+
task.presentation = {
|
|
101
|
+
reveal: "always",
|
|
102
|
+
panel: "dedicated",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (spec.label === "olcx: watch") {
|
|
106
|
+
task.isBackground = true;
|
|
107
|
+
task.presentation = {
|
|
108
|
+
reveal: "always",
|
|
109
|
+
panel: "dedicated",
|
|
110
|
+
clear: false,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return task;
|
|
114
|
+
}
|
|
115
|
+
function isOlcxManagedTask(value) {
|
|
116
|
+
return (typeof value === "object" &&
|
|
117
|
+
value !== null &&
|
|
118
|
+
typeof value.label === "string" &&
|
|
119
|
+
OLCX_MANAGED_TASK_LABELS.has(value.label));
|
|
120
|
+
}
|
|
121
|
+
function assertRecord(value, path) {
|
|
122
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
123
|
+
throw createOlcxError({
|
|
124
|
+
code: "PROJECT_CONFIG_INVALID",
|
|
125
|
+
message: `${path} must contain a JSON object.`,
|
|
126
|
+
hint: `Fix ${path} before running olcx init again.`,
|
|
127
|
+
details: { path },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function isNodeError(error, code) {
|
|
132
|
+
return typeof error === "object" && error !== null && error.code === code;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=vscode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vscode.js","sourceRoot":"","sources":["../../src/config/vscode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DoctorReport } from "./types.js";
|
|
2
|
+
export interface RunDoctorDiagnosticsOptions {
|
|
3
|
+
cwd: string;
|
|
4
|
+
nodeVersion?: string;
|
|
5
|
+
backendAvailable?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function runDoctorDiagnostics(options: RunDoctorDiagnosticsOptions): Promise<DoctorReport>;
|
|
8
|
+
export declare function formatDoctorReport(report: DoctorReport): string;
|