@netique/overleaf-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +693 -0
- package/README.md +152 -0
- package/dist/api/commentTypes.js +5 -0
- package/dist/api/commentTypes.js.map +1 -0
- package/dist/api/compileTypes.js +2 -0
- package/dist/api/compileTypes.js.map +1 -0
- package/dist/api/errors.js +17 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/http.js +52 -0
- package/dist/api/http.js.map +1 -0
- package/dist/api/projectTypes.js +38 -0
- package/dist/api/projectTypes.js.map +1 -0
- package/dist/api/socket.js +348 -0
- package/dist/api/socket.js.map +1 -0
- package/dist/api/types.js +18 -0
- package/dist/api/types.js.map +1 -0
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/ot/diff.js +32 -0
- package/dist/ot/diff.js.map +1 -0
- package/dist/ot/trackedChanges.js +19 -0
- package/dist/ot/trackedChanges.js.map +1 -0
- package/dist/session/activeProject.js +45 -0
- package/dist/session/activeProject.js.map +1 -0
- package/dist/session/docCache.js +21 -0
- package/dist/session/docCache.js.map +1 -0
- package/dist/session/identity.js +59 -0
- package/dist/session/identity.js.map +1 -0
- package/dist/tools/comments.js +195 -0
- package/dist/tools/comments.js.map +1 -0
- package/dist/tools/compile.js +188 -0
- package/dist/tools/compile.js.map +1 -0
- package/dist/tools/editFile.js +123 -0
- package/dist/tools/editFile.js.map +1 -0
- package/dist/tools/listFiles.js +42 -0
- package/dist/tools/listFiles.js.map +1 -0
- package/dist/tools/listProjects.js +88 -0
- package/dist/tools/listProjects.js.map +1 -0
- package/dist/tools/openProject.js +58 -0
- package/dist/tools/openProject.js.map +1 -0
- package/dist/tools/readFile.js +133 -0
- package/dist/tools/readFile.js.map +1 -0
- package/dist/tools/trackedChanges.js +260 -0
- package/dist/tools/trackedChanges.js.map +1 -0
- package/dist/util/logger.js +18 -0
- package/dist/util/logger.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { asJson, olGet, olPostJson, expectOk } from "../api/http.js";
|
|
3
|
+
import { getActiveProject, setLastCompile } from "../session/activeProject.js";
|
|
4
|
+
import { logger } from "../util/logger.js";
|
|
5
|
+
const Schema = z.object({
|
|
6
|
+
root_doc: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Project-relative path to use as the LaTeX root (e.g. 'main.tex'). Defaults to the project's configured root doc."),
|
|
10
|
+
draft: z
|
|
11
|
+
.boolean()
|
|
12
|
+
.default(false)
|
|
13
|
+
.describe("Draft mode — faster but uses placeholder images for figures."),
|
|
14
|
+
stop_on_first_error: z
|
|
15
|
+
.boolean()
|
|
16
|
+
.default(false)
|
|
17
|
+
.describe("Stop on the first LaTeX error instead of continuing to produce a partial PDF."),
|
|
18
|
+
});
|
|
19
|
+
function summarizeErrors(log) {
|
|
20
|
+
if (!log)
|
|
21
|
+
return { errors: [], warnings: 0 };
|
|
22
|
+
const errors = [];
|
|
23
|
+
let warnings = 0;
|
|
24
|
+
for (const line of log.split("\n")) {
|
|
25
|
+
if (/^! /.test(line))
|
|
26
|
+
errors.push(line.trim());
|
|
27
|
+
else if (/warning/i.test(line))
|
|
28
|
+
warnings++;
|
|
29
|
+
}
|
|
30
|
+
return { errors: errors.slice(0, 20), warnings };
|
|
31
|
+
}
|
|
32
|
+
// Build the GET-able URL for an output file from a compile response, including
|
|
33
|
+
// the clsiserverid + compileGroup query params CLSI requires.
|
|
34
|
+
function buildOutputUrl(file, last) {
|
|
35
|
+
const params = new URLSearchParams();
|
|
36
|
+
if (last.clsiServerId)
|
|
37
|
+
params.set("clsiserverid", last.clsiServerId);
|
|
38
|
+
if (last.compileGroup)
|
|
39
|
+
params.set("compileGroup", last.compileGroup);
|
|
40
|
+
const base = file.url.replace(/^\/+/, "");
|
|
41
|
+
const sep = base.includes("?") ? "&" : "?";
|
|
42
|
+
const qs = params.toString();
|
|
43
|
+
return qs ? `${base}${sep}${qs}` : base;
|
|
44
|
+
}
|
|
45
|
+
async function fetchOutputLog(last) {
|
|
46
|
+
const logFile = last.outputFiles?.find((f) => f.path === "output.log");
|
|
47
|
+
if (!logFile)
|
|
48
|
+
return undefined;
|
|
49
|
+
const path = buildOutputUrl(logFile, last);
|
|
50
|
+
const res = await olGet(path);
|
|
51
|
+
await expectOk(res, `GET ${path}`);
|
|
52
|
+
return await res.text();
|
|
53
|
+
}
|
|
54
|
+
export function registerCompile(server) {
|
|
55
|
+
server.registerTool("compile", {
|
|
56
|
+
title: "Compile the open Overleaf project",
|
|
57
|
+
description: "Triggers a LaTeX compile on Overleaf's CLSI, then fetches `output.log` and returns a unified summary: " +
|
|
58
|
+
"status, whether a PDF was produced, error_count (parsed `! `-prefixed log lines), warning_count, first error lines, output file list, timings. " +
|
|
59
|
+
"Note: Overleaf returns status:\"success\" even when LaTeX has errors (PDF is still generated under nonstopmode). " +
|
|
60
|
+
"The truthful 'did it build cleanly?' check is `error_count === 0`. " +
|
|
61
|
+
"Use `read_log` for the full log when more context is needed.",
|
|
62
|
+
inputSchema: Schema.shape,
|
|
63
|
+
}, async (args) => {
|
|
64
|
+
const ap = getActiveProject();
|
|
65
|
+
if (!ap) {
|
|
66
|
+
return { content: [{ type: "text", text: "No project is open. Call open_project first." }], isError: true };
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const body = {
|
|
70
|
+
check: "silent",
|
|
71
|
+
draft: args.draft,
|
|
72
|
+
incrementalCompilesEnabled: true,
|
|
73
|
+
rootResourcePath: args.root_doc ?? null,
|
|
74
|
+
stopOnFirstError: args.stop_on_first_error,
|
|
75
|
+
};
|
|
76
|
+
const res = await olPostJson(`project/${ap.projectId}/compile?auto_compile=true`, body);
|
|
77
|
+
const result = await asJson(res, `POST project/${ap.projectId}/compile`);
|
|
78
|
+
setLastCompile(result);
|
|
79
|
+
const pdf = result.outputFiles?.find((f) => f.path === "output.pdf");
|
|
80
|
+
const logFile = result.outputFiles?.find((f) => f.path === "output.log");
|
|
81
|
+
let errorCount = 0;
|
|
82
|
+
let warningCount = 0;
|
|
83
|
+
let errorLines = [];
|
|
84
|
+
let logBytes = 0;
|
|
85
|
+
if (logFile) {
|
|
86
|
+
try {
|
|
87
|
+
const log = await fetchOutputLog(result);
|
|
88
|
+
if (log) {
|
|
89
|
+
logBytes = log.length;
|
|
90
|
+
const summarized = summarizeErrors(log);
|
|
91
|
+
errorLines = summarized.errors;
|
|
92
|
+
errorCount = errorLines.length;
|
|
93
|
+
warningCount = summarized.warnings;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (logErr) {
|
|
97
|
+
logger.warn("compile: log fetch failed; not fatal", logErr instanceof Error ? logErr.message : logErr);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const summary = {
|
|
101
|
+
status: result.status ?? "unknown",
|
|
102
|
+
built_cleanly: errorCount === 0 && Boolean(pdf),
|
|
103
|
+
pdf_available: Boolean(pdf),
|
|
104
|
+
error_count: errorCount,
|
|
105
|
+
warning_count: warningCount,
|
|
106
|
+
first_errors: errorLines.slice(0, 5),
|
|
107
|
+
log_bytes: logBytes,
|
|
108
|
+
compile_time_ms: result.timings?.compile,
|
|
109
|
+
total_time_ms: result.timings?.compileE2E,
|
|
110
|
+
output_files: (result.outputFiles ?? []).map((f) => f.path),
|
|
111
|
+
};
|
|
112
|
+
const headline = summary.built_cleanly
|
|
113
|
+
? `Built cleanly. PDF produced, 0 LaTeX errors.`
|
|
114
|
+
: errorCount > 0
|
|
115
|
+
? `LaTeX errors detected (${errorCount}). ${pdf ? "Partial PDF produced." : "No PDF."} First error: ${errorLines[0] ?? "(see read_log)"}`
|
|
116
|
+
: !pdf
|
|
117
|
+
? `No PDF produced. status=${summary.status}.`
|
|
118
|
+
: `Compile status: ${summary.status}.`;
|
|
119
|
+
return {
|
|
120
|
+
content: [
|
|
121
|
+
{
|
|
122
|
+
type: "text",
|
|
123
|
+
text: `${headline} ` +
|
|
124
|
+
(summary.compile_time_ms ? `Compile took ${summary.compile_time_ms}ms. ` : "") +
|
|
125
|
+
(warningCount ? `${warningCount} warning(s). ` : "") +
|
|
126
|
+
(errorCount > 0 ? `Use \`read_log\` for full log.` : ""),
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
structuredContent: summary,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
134
|
+
logger.error("compile failed", msg);
|
|
135
|
+
return { content: [{ type: "text", text: `Compile failed: ${msg}` }], isError: true };
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
export function registerReadLog(server) {
|
|
140
|
+
server.registerTool("read_log", {
|
|
141
|
+
title: "Read the last compile's output.log",
|
|
142
|
+
description: "Returns the full LaTeX log from the most recent `compile` call. " +
|
|
143
|
+
"`compile` already includes the error count + first few errors in its response — use this only when you need more context (full log, line numbers, package warnings, etc.). " +
|
|
144
|
+
"Includes a summary of `!`-prefixed error lines at the top, then the full log (truncated to the last 8000 chars).",
|
|
145
|
+
inputSchema: {},
|
|
146
|
+
annotations: { readOnlyHint: true },
|
|
147
|
+
}, async () => {
|
|
148
|
+
const ap = getActiveProject();
|
|
149
|
+
if (!ap)
|
|
150
|
+
return { content: [{ type: "text", text: "No project is open." }], isError: true };
|
|
151
|
+
const last = ap.lastCompile;
|
|
152
|
+
if (!last) {
|
|
153
|
+
return { content: [{ type: "text", text: "No compile has been run for the open project yet. Call `compile` first." }], isError: true };
|
|
154
|
+
}
|
|
155
|
+
const logFile = last.outputFiles?.find((f) => f.path === "output.log");
|
|
156
|
+
if (!logFile) {
|
|
157
|
+
return { content: [{ type: "text", text: "The last compile produced no output.log (it may have failed before reaching LaTeX)." }], isError: true };
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const fullLog = await fetchOutputLog(last);
|
|
161
|
+
if (fullLog == null) {
|
|
162
|
+
return { content: [{ type: "text", text: "No output.log available." }], isError: true };
|
|
163
|
+
}
|
|
164
|
+
const { errors, warnings } = summarizeErrors(fullLog);
|
|
165
|
+
const tail = fullLog.length > 8000 ? fullLog.slice(-8000) : fullLog;
|
|
166
|
+
const errorBlock = errors.length
|
|
167
|
+
? `=== ${errors.length} error line(s) ===\n${errors.join("\n")}\n\n`
|
|
168
|
+
: "=== no '! ' error lines ===\n\n";
|
|
169
|
+
const text = errorBlock +
|
|
170
|
+
(fullLog.length > 8000 ? `=== output.log (last 8000 of ${fullLog.length} chars) ===\n` : "=== output.log ===\n") +
|
|
171
|
+
tail;
|
|
172
|
+
return {
|
|
173
|
+
content: [{ type: "text", text }],
|
|
174
|
+
structuredContent: {
|
|
175
|
+
log_bytes: fullLog.length,
|
|
176
|
+
error_lines: errors,
|
|
177
|
+
warning_count: warnings,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
183
|
+
logger.error("read_log failed", msg);
|
|
184
|
+
return { content: [{ type: "text", text: `Failed to fetch output.log: ${msg}` }], isError: true };
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=compile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/tools/compile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { applyOtUpdate, getActiveSocket } from "../api/socket.js";
|
|
3
|
+
import { getIdentity } from "../session/identity.js";
|
|
4
|
+
import { ensureDocLoaded, updateDoc } from "../session/docCache.js";
|
|
5
|
+
import { findByPath, getActiveProject } from "../session/activeProject.js";
|
|
6
|
+
import { textToOps } from "../ot/diff.js";
|
|
7
|
+
import { generateIdSeed } from "../ot/trackedChanges.js";
|
|
8
|
+
import { logger } from "../util/logger.js";
|
|
9
|
+
const Schema = z.object({
|
|
10
|
+
path: z
|
|
11
|
+
.string()
|
|
12
|
+
.min(1)
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Project-relative path of the doc to edit, e.g. 'main.tex' or 'chapters/intro.tex'. If omitted, defaults to the project's root doc."),
|
|
15
|
+
new_content: z
|
|
16
|
+
.string()
|
|
17
|
+
.describe("Desired full content of the file. The server computes a diff against the current content and submits the minimal OT operation."),
|
|
18
|
+
expected_version: z
|
|
19
|
+
.number()
|
|
20
|
+
.int()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Optional safety check. If provided and the doc's current version differs, the edit is rejected."),
|
|
23
|
+
track: z
|
|
24
|
+
.enum(["auto", "on", "off"])
|
|
25
|
+
.default("on")
|
|
26
|
+
.describe("Tracked-changes mode. Default is 'on' — every edit lands as a pending suggestion in Overleaf's Review panel, which is what collaborators expect for an agent. Set 'off' explicitly to make a direct (untracked) edit. 'auto' tracks only when the project has track-changes enabled for this user."),
|
|
27
|
+
});
|
|
28
|
+
export function registerEditFile(server) {
|
|
29
|
+
server.registerTool("edit_file", {
|
|
30
|
+
title: "Edit a .tex doc in the open Overleaf project",
|
|
31
|
+
description: "Replaces the contents of a doc by computing a minimal diff and submitting it as an OT operation " +
|
|
32
|
+
"over the live Socket.IO connection. The change lands in the web editor in real time. " +
|
|
33
|
+
"By default the edit appears as a pending suggestion in the Review panel (track:'on'); pass track:'off' to write directly. " +
|
|
34
|
+
"If `path` is omitted, defaults to the project's root doc. " +
|
|
35
|
+
"Only .tex / .bib / .md / similar text docs are editable — binary files are not.",
|
|
36
|
+
inputSchema: Schema.shape,
|
|
37
|
+
}, async (args) => {
|
|
38
|
+
const ap = getActiveProject();
|
|
39
|
+
if (!ap) {
|
|
40
|
+
return { content: [{ type: "text", text: "No project is open. Call open_project first." }], isError: true };
|
|
41
|
+
}
|
|
42
|
+
const resolvedPath = args.path ?? ap.rootDocPath;
|
|
43
|
+
if (!resolvedPath) {
|
|
44
|
+
return { content: [{ type: "text", text: "No path provided and the project has no configured root doc. Pass a `path`." }], isError: true };
|
|
45
|
+
}
|
|
46
|
+
const entity = findByPath(resolvedPath);
|
|
47
|
+
if (!entity) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: `Path not found in project: '${resolvedPath}'. Use list_files to inspect available paths.` }],
|
|
50
|
+
isError: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (entity.kind !== "doc") {
|
|
54
|
+
return { content: [{ type: "text", text: `'${resolvedPath}' is a ${entity.kind}, not an editable doc.` }], isError: true };
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const cached = await ensureDocLoaded(entity.id);
|
|
58
|
+
if (args.expected_version !== undefined && cached.version !== args.expected_version) {
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: "text", text: `Version mismatch: cached version is ${cached.version}, you provided ${args.expected_version}. Re-read the file and retry.` }],
|
|
61
|
+
isError: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const ops = textToOps(cached.text, args.new_content);
|
|
65
|
+
if (ops.length === 0) {
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: "text", text: "No-op: new_content is identical to the current doc." }],
|
|
68
|
+
structuredContent: { path: entity.path, doc_id: entity.id, version: cached.version, ops_applied: 0 },
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const identity = await getIdentity();
|
|
72
|
+
const sock = getActiveSocket();
|
|
73
|
+
const shouldTrack = args.track === "on" ? true : args.track === "off" ? false : ap.trackChangesOnForMe;
|
|
74
|
+
const meta = {
|
|
75
|
+
source: sock?.publicId ?? "overleaf-mcp",
|
|
76
|
+
ts: Date.now(),
|
|
77
|
+
user_id: identity.userId,
|
|
78
|
+
};
|
|
79
|
+
if (shouldTrack)
|
|
80
|
+
meta.tc = generateIdSeed();
|
|
81
|
+
const update = {
|
|
82
|
+
doc: entity.id,
|
|
83
|
+
op: ops,
|
|
84
|
+
v: cached.version,
|
|
85
|
+
meta,
|
|
86
|
+
};
|
|
87
|
+
await applyOtUpdate(entity.id, update);
|
|
88
|
+
const newVersion = cached.version + 1;
|
|
89
|
+
updateDoc(entity.id, args.new_content, newVersion);
|
|
90
|
+
const insertedChars = ops.reduce((n, op) => n + (op.i?.length ?? 0), 0);
|
|
91
|
+
const deletedChars = ops.reduce((n, op) => n + (op.d?.length ?? 0), 0);
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: "text",
|
|
96
|
+
text: `Applied ${ops.length} op(s) to '${entity.path}' (+${insertedChars} / -${deletedChars} chars). ` +
|
|
97
|
+
`Doc version ${cached.version} -> ${newVersion}. ` +
|
|
98
|
+
(shouldTrack
|
|
99
|
+
? "Submitted as tracked changes — should appear as a pending suggestion in Overleaf's review panel."
|
|
100
|
+
: "Submitted as a direct edit (no tracking)."),
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
structuredContent: {
|
|
104
|
+
path: entity.path,
|
|
105
|
+
doc_id: entity.id,
|
|
106
|
+
ops_applied: ops.length,
|
|
107
|
+
chars_inserted: insertedChars,
|
|
108
|
+
chars_deleted: deletedChars,
|
|
109
|
+
version_before: cached.version,
|
|
110
|
+
version_after: newVersion,
|
|
111
|
+
tracked: shouldTrack,
|
|
112
|
+
track_mode: args.track,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
118
|
+
logger.error("edit_file failed", msg);
|
|
119
|
+
return { content: [{ type: "text", text: `Failed to edit '${args.path}': ${msg}` }], isError: true };
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=editFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editFile.js","sourceRoot":"","sources":["../../src/tools/editFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getActiveProject } from "../session/activeProject.js";
|
|
3
|
+
const Schema = z.object({
|
|
4
|
+
kind: z
|
|
5
|
+
.enum(["all", "doc", "file", "folder"])
|
|
6
|
+
.default("all")
|
|
7
|
+
.describe("Filter by entity kind. 'doc' = editable .tex/.md files, 'file' = binary assets (images, PDFs), 'folder' = directories."),
|
|
8
|
+
path_contains: z.string().optional().describe("Case-insensitive substring filter on the project-relative path."),
|
|
9
|
+
});
|
|
10
|
+
export function registerListFiles(server) {
|
|
11
|
+
server.registerTool("list_files", {
|
|
12
|
+
title: "List files in the open Overleaf project",
|
|
13
|
+
description: "Returns the file tree of the currently open project as a flat list of project-relative paths. " +
|
|
14
|
+
"Cheap — uses cached data from open_project, no network. " +
|
|
15
|
+
"Each entity has a path (e.g. 'chapters/intro.tex'), an id, and a kind ('doc' | 'file' | 'folder').",
|
|
16
|
+
inputSchema: Schema.shape,
|
|
17
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
18
|
+
}, async (args) => {
|
|
19
|
+
const ap = getActiveProject();
|
|
20
|
+
if (!ap) {
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: "text", text: "No project is open. Call open_project first." }],
|
|
23
|
+
isError: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
let entities = ap.entities;
|
|
27
|
+
if (args.kind !== "all")
|
|
28
|
+
entities = entities.filter((e) => e.kind === args.kind);
|
|
29
|
+
if (args.path_contains) {
|
|
30
|
+
const needle = args.path_contains.toLowerCase();
|
|
31
|
+
entities = entities.filter((e) => e.path.toLowerCase().includes(needle));
|
|
32
|
+
}
|
|
33
|
+
entities = [...entities].sort((a, b) => a.path.localeCompare(b.path));
|
|
34
|
+
const lines = entities.map((e) => `${e.kind.padEnd(6)} ${e.path}`);
|
|
35
|
+
const text = lines.length === 0 ? "(no entities matched)" : lines.join("\n");
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: "text", text }],
|
|
38
|
+
structuredContent: { project_id: ap.projectId, count: entities.length, entities },
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=listFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listFiles.js","sourceRoot":"","sources":["../../src/tools/listFiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;SACtC,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,wHAAwH,CAAC;IACrI,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;CACjH,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,KAAK,EAAE,yCAAyC;QAChD,WAAW,EACT,gGAAgG;YAChG,0DAA0D;YAC1D,oGAAoG;QACtG,WAAW,EAAE,MAAM,CAAC,KAAK;QACzB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE;KAC1D,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;QAC9B,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,8CAA8C,EAAE,CAAC;gBACjF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,IAAI,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC;QAC3B,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;YAAE,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC;QACjF,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;YAChD,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7E,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACjC,iBAAiB,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE;SAClF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { asJson, olGet, olPostJson } from "../api/http.js";
|
|
3
|
+
import { normalizeProject } from "../api/types.js";
|
|
4
|
+
import { logger } from "../util/logger.js";
|
|
5
|
+
async function fetchProjects() {
|
|
6
|
+
// POST /api/project is the dashboard XHR — returns lastUpdated, owner, etc.
|
|
7
|
+
// GET /user/projects exists on older / self-hosted Overleaf but returns a
|
|
8
|
+
// minimal payload (id + name + accessLevel only). Prefer the rich endpoint.
|
|
9
|
+
let raw;
|
|
10
|
+
const r1 = await olPostJson("api/project", {});
|
|
11
|
+
if (r1.ok) {
|
|
12
|
+
raw = (await r1.json()).projects;
|
|
13
|
+
}
|
|
14
|
+
else if (r1.status === 404 || r1.status === 405) {
|
|
15
|
+
const r2 = await olGet("user/projects");
|
|
16
|
+
raw = (await asJson(r2, "GET /user/projects")).projects;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
await asJson(r1, "POST /api/project");
|
|
20
|
+
}
|
|
21
|
+
if (!raw)
|
|
22
|
+
return [];
|
|
23
|
+
return raw.map(normalizeProject).sort((a, b) => {
|
|
24
|
+
const ta = a.lastUpdated ? Date.parse(a.lastUpdated) : 0;
|
|
25
|
+
const tb = b.lastUpdated ? Date.parse(b.lastUpdated) : 0;
|
|
26
|
+
return tb - ta;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const FilterSchema = z.object({
|
|
30
|
+
include_archived: z
|
|
31
|
+
.boolean()
|
|
32
|
+
.default(false)
|
|
33
|
+
.describe("Include archived projects in the result (default: false)."),
|
|
34
|
+
include_trashed: z
|
|
35
|
+
.boolean()
|
|
36
|
+
.default(false)
|
|
37
|
+
.describe("Include trashed projects in the result (default: false)."),
|
|
38
|
+
name_contains: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe("Case-insensitive substring filter on project name."),
|
|
42
|
+
limit: z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.min(1)
|
|
46
|
+
.max(500)
|
|
47
|
+
.default(30)
|
|
48
|
+
.describe("Maximum number of projects to return, after sorting by most recently updated (default: 30)."),
|
|
49
|
+
});
|
|
50
|
+
export function registerListProjects(server) {
|
|
51
|
+
server.registerTool("list_projects", {
|
|
52
|
+
title: "List Overleaf projects",
|
|
53
|
+
description: "Lists projects on the configured Overleaf account, sorted by most recently updated. " +
|
|
54
|
+
"Returns each project's id, name, last update time, and owner. " +
|
|
55
|
+
"Use the returned id with `open_project` to start working on a project.",
|
|
56
|
+
inputSchema: FilterSchema.shape,
|
|
57
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
58
|
+
}, async (args) => {
|
|
59
|
+
try {
|
|
60
|
+
let projects = await fetchProjects();
|
|
61
|
+
const totalBeforeFilter = projects.length;
|
|
62
|
+
if (!args.include_archived)
|
|
63
|
+
projects = projects.filter((p) => !p.archived);
|
|
64
|
+
if (!args.include_trashed)
|
|
65
|
+
projects = projects.filter((p) => !p.trashed);
|
|
66
|
+
if (args.name_contains) {
|
|
67
|
+
const needle = args.name_contains.toLowerCase();
|
|
68
|
+
projects = projects.filter((p) => p.name.toLowerCase().includes(needle));
|
|
69
|
+
}
|
|
70
|
+
const truncated = projects.length > args.limit;
|
|
71
|
+
const shown = projects.slice(0, args.limit);
|
|
72
|
+
const payload = { count: shown.length, total_matched: projects.length, total_account: totalBeforeFilter, truncated, projects: shown };
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
75
|
+
structuredContent: payload,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
80
|
+
logger.error("list_projects failed", msg);
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: "text", text: `Failed to list projects: ${msg}` }],
|
|
83
|
+
isError: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=listProjects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listProjects.js","sourceRoot":"","sources":["../../src/tools/listProjects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { open } from "../session/activeProject.js";
|
|
3
|
+
import { logger } from "../util/logger.js";
|
|
4
|
+
const Schema = z.object({
|
|
5
|
+
project_id: z
|
|
6
|
+
.string()
|
|
7
|
+
.min(8)
|
|
8
|
+
.describe("The Overleaf project id, from list_projects (a hex string like '61d853bcbf1003100e957034')."),
|
|
9
|
+
});
|
|
10
|
+
export function registerOpenProject(server) {
|
|
11
|
+
server.registerTool("open_project", {
|
|
12
|
+
title: "Open Overleaf project",
|
|
13
|
+
description: "Joins the project's real-time Socket.IO session and caches its file tree. " +
|
|
14
|
+
"Must be called before list_files / read_file / edit_file. " +
|
|
15
|
+
"Switching projects automatically closes the previous session.",
|
|
16
|
+
inputSchema: Schema.shape,
|
|
17
|
+
}, async (args) => {
|
|
18
|
+
try {
|
|
19
|
+
const p = await open(args.project_id);
|
|
20
|
+
const project = p.project;
|
|
21
|
+
const summary = {
|
|
22
|
+
project_id: p.projectId,
|
|
23
|
+
name: p.name,
|
|
24
|
+
root_doc_path: p.rootDocPath,
|
|
25
|
+
root_doc_id: p.rootDocId,
|
|
26
|
+
entity_count: p.entities.length,
|
|
27
|
+
docs: p.entities.filter((e) => e.kind === "doc").length,
|
|
28
|
+
files: p.entities.filter((e) => e.kind === "file").length,
|
|
29
|
+
folders: p.entities.filter((e) => e.kind === "folder").length,
|
|
30
|
+
track_changes_on_for_me: p.trackChangesOnForMe,
|
|
31
|
+
compiler: project.compiler,
|
|
32
|
+
spell_check_language: project.spellCheckLanguage,
|
|
33
|
+
public_access_level: project.publicAccesLevel,
|
|
34
|
+
owner: project.owner ? { email: project.owner.email, name: [project.owner.first_name, project.owner.last_name].filter(Boolean).join(" ") || undefined } : undefined,
|
|
35
|
+
members: (project.members ?? []).map((m) => ({ email: m.email, name: [m.first_name, m.last_name].filter(Boolean).join(" ") || undefined, privileges: m.privileges })),
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: `Opened "${p.name}" (${summary.docs} docs, ${summary.files} files, ${summary.folders} folders). ` +
|
|
42
|
+
`Track changes ${summary.track_changes_on_for_me ? "is ON" : "is OFF"} for this user. ` +
|
|
43
|
+
`Root doc: ${p.rootDocPath ?? "(unset)"}. ` +
|
|
44
|
+
`Compiler: ${summary.compiler ?? "(default)"}. ` +
|
|
45
|
+
`Use list_files to browse, read_file/edit_file to read+write (path defaults to the root doc).`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
structuredContent: summary,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53
|
+
logger.error("open_project failed", msg);
|
|
54
|
+
return { content: [{ type: "text", text: `Failed to open project: ${msg}` }], isError: true };
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=openProject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openProject.js","sourceRoot":"","sources":["../../src/tools/openProject.ts"],"names":[],"mappings":"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"}
|