@documonster/mcp 0.8.0-canary.sha.09791dab

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.
Files changed (127) hide show
  1. package/LICENSE +205 -0
  2. package/README.md +253 -0
  3. package/dist/capabilities.d.ts +29 -0
  4. package/dist/capabilities.d.ts.map +1 -0
  5. package/dist/capabilities.js +188 -0
  6. package/dist/capabilities.js.map +1 -0
  7. package/dist/cli.d.ts +13 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +64 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.d.ts +65 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +189 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/errors.d.ts +66 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +96 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/index.d.ts +25 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +20 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/sandbox.d.ts +86 -0
  24. package/dist/sandbox.d.ts.map +1 -0
  25. package/dist/sandbox.js +224 -0
  26. package/dist/sandbox.js.map +1 -0
  27. package/dist/server.d.ts +22 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +66 -0
  30. package/dist/server.js.map +1 -0
  31. package/dist/tools/archive-read.d.ts +31 -0
  32. package/dist/tools/archive-read.d.ts.map +1 -0
  33. package/dist/tools/archive-read.js +315 -0
  34. package/dist/tools/archive-read.js.map +1 -0
  35. package/dist/tools/archive-write.d.ts +9 -0
  36. package/dist/tools/archive-write.d.ts.map +1 -0
  37. package/dist/tools/archive-write.js +219 -0
  38. package/dist/tools/archive-write.js.map +1 -0
  39. package/dist/tools/chart.d.ts +93 -0
  40. package/dist/tools/chart.d.ts.map +1 -0
  41. package/dist/tools/chart.js +263 -0
  42. package/dist/tools/chart.js.map +1 -0
  43. package/dist/tools/doc-convert.d.ts +13 -0
  44. package/dist/tools/doc-convert.d.ts.map +1 -0
  45. package/dist/tools/doc-convert.js +209 -0
  46. package/dist/tools/doc-convert.js.map +1 -0
  47. package/dist/tools/doc-paginate.d.ts +14 -0
  48. package/dist/tools/doc-paginate.d.ts.map +1 -0
  49. package/dist/tools/doc-paginate.js +153 -0
  50. package/dist/tools/doc-paginate.js.map +1 -0
  51. package/dist/tools/doc-read.d.ts +14 -0
  52. package/dist/tools/doc-read.d.ts.map +1 -0
  53. package/dist/tools/doc-read.js +175 -0
  54. package/dist/tools/doc-read.js.map +1 -0
  55. package/dist/tools/doc-review.d.ts +17 -0
  56. package/dist/tools/doc-review.d.ts.map +1 -0
  57. package/dist/tools/doc-review.js +249 -0
  58. package/dist/tools/doc-review.js.map +1 -0
  59. package/dist/tools/doc-search.d.ts +20 -0
  60. package/dist/tools/doc-search.d.ts.map +1 -0
  61. package/dist/tools/doc-search.js +268 -0
  62. package/dist/tools/doc-search.js.map +1 -0
  63. package/dist/tools/doc-write.d.ts +11 -0
  64. package/dist/tools/doc-write.d.ts.map +1 -0
  65. package/dist/tools/doc-write.js +81 -0
  66. package/dist/tools/doc-write.js.map +1 -0
  67. package/dist/tools/document.d.ts +74 -0
  68. package/dist/tools/document.d.ts.map +1 -0
  69. package/dist/tools/document.js +157 -0
  70. package/dist/tools/document.js.map +1 -0
  71. package/dist/tools/form-fill.d.ts +20 -0
  72. package/dist/tools/form-fill.d.ts.map +1 -0
  73. package/dist/tools/form-fill.js +270 -0
  74. package/dist/tools/form-fill.js.map +1 -0
  75. package/dist/tools/formula-evaluate.d.ts +14 -0
  76. package/dist/tools/formula-evaluate.d.ts.map +1 -0
  77. package/dist/tools/formula-evaluate.js +192 -0
  78. package/dist/tools/formula-evaluate.js.map +1 -0
  79. package/dist/tools/fs-helpers.d.ts +106 -0
  80. package/dist/tools/fs-helpers.d.ts.map +1 -0
  81. package/dist/tools/fs-helpers.js +257 -0
  82. package/dist/tools/fs-helpers.js.map +1 -0
  83. package/dist/tools/help.d.ts +227 -0
  84. package/dist/tools/help.d.ts.map +1 -0
  85. package/dist/tools/help.js +262 -0
  86. package/dist/tools/help.js.map +1 -0
  87. package/dist/tools/index.d.ts +33 -0
  88. package/dist/tools/index.d.ts.map +1 -0
  89. package/dist/tools/index.js +78 -0
  90. package/dist/tools/index.js.map +1 -0
  91. package/dist/tools/inspect.d.ts +14 -0
  92. package/dist/tools/inspect.d.ts.map +1 -0
  93. package/dist/tools/inspect.js +463 -0
  94. package/dist/tools/inspect.js.map +1 -0
  95. package/dist/tools/pdf-edit.d.ts +26 -0
  96. package/dist/tools/pdf-edit.d.ts.map +1 -0
  97. package/dist/tools/pdf-edit.js +390 -0
  98. package/dist/tools/pdf-edit.js.map +1 -0
  99. package/dist/tools/result.d.ts +25 -0
  100. package/dist/tools/result.d.ts.map +1 -0
  101. package/dist/tools/result.js +43 -0
  102. package/dist/tools/result.js.map +1 -0
  103. package/dist/tools/sheet-edit.d.ts +16 -0
  104. package/dist/tools/sheet-edit.d.ts.map +1 -0
  105. package/dist/tools/sheet-edit.js +325 -0
  106. package/dist/tools/sheet-edit.js.map +1 -0
  107. package/dist/tools/sheet-read.d.ts +10 -0
  108. package/dist/tools/sheet-read.d.ts.map +1 -0
  109. package/dist/tools/sheet-read.js +139 -0
  110. package/dist/tools/sheet-read.js.map +1 -0
  111. package/dist/tools/sheet-write.d.ts +15 -0
  112. package/dist/tools/sheet-write.d.ts.map +1 -0
  113. package/dist/tools/sheet-write.js +290 -0
  114. package/dist/tools/sheet-write.js.map +1 -0
  115. package/dist/tools/spreadsheet.d.ts +100 -0
  116. package/dist/tools/spreadsheet.d.ts.map +1 -0
  117. package/dist/tools/spreadsheet.js +210 -0
  118. package/dist/tools/spreadsheet.js.map +1 -0
  119. package/dist/tools/template.d.ts +18 -0
  120. package/dist/tools/template.d.ts.map +1 -0
  121. package/dist/tools/template.js +209 -0
  122. package/dist/tools/template.js.map +1 -0
  123. package/dist/tools/types.d.ts +79 -0
  124. package/dist/tools/types.d.ts.map +1 -0
  125. package/dist/tools/types.js +18 -0
  126. package/dist/tools/types.js.map +1 -0
  127. package/package.json +74 -0
@@ -0,0 +1,390 @@
1
+ /**
2
+ * `pdf_edit` — structural and overlay edits to an existing PDF.
3
+ *
4
+ * The operations here are the ones that need no understanding of the content:
5
+ * stamp a watermark, add page numbers, drop or keep pages, rotate, append
6
+ * another PDF. That is exactly the set a model can drive safely, because
7
+ * getting them wrong is visible rather than subtle.
8
+ *
9
+ * Overlays are drawn on a separate content stream layered over the original, so
10
+ * existing page content is never redrawn.
11
+ *
12
+ * How the file is saved depends on what was asked for, and it matters:
13
+ *
14
+ * - **Overlay-only** edits (watermark, page numbers, stamp) are saved as an
15
+ * incremental update where the format allows it, which appends to the original
16
+ * bytes and therefore keeps bookmarks, form fields and any signature intact.
17
+ * - **Structural** edits (delete/keep pages, rotate, append) require a full
18
+ * rebuild. That renumbers objects, invalidates signatures and may drop
19
+ * document-level structures the rebuilder does not carry over. The result says
20
+ * so rather than leaving the caller to discover it.
21
+ *
22
+ * Deliberately absent: extracting or reflowing text into a new PDF, which no
23
+ * faithful implementation exists for.
24
+ */
25
+ import { readFile } from "node:fs/promises";
26
+ import { Pdf } from "documonster/pdf";
27
+ import { z } from "zod";
28
+ import { toolError } from "../errors.js";
29
+ import { assertWritable, resolveEditTarget, resolveInRoot } from "../sandbox.js";
30
+ import { parsePages, supportsIncrementalUpdate } from "./document.js";
31
+ import { assertReadableSize, assertUnchanged, backupOnce, describeBackup, fingerprint, isSameFile, writeBytesWithPolicy, writeFileAtomic } from "./fs-helpers.js";
32
+ import { formatBytes, textResult } from "./result.js";
33
+ import { defineTool } from "./types.js";
34
+ /** Operations that cannot be expressed as an appended incremental update. */
35
+ const STRUCTURAL_OPS = new Set(["delete_pages", "keep_pages", "rotate", "append"]);
36
+ /** Pages a single call may touch. */
37
+ const MAX_PAGES = 2_000;
38
+ const opSchema = z.discriminatedUnion("op", [
39
+ z.object({
40
+ op: z.literal("watermark"),
41
+ text: z.string().min(1).describe('Watermark text, e.g. "DRAFT" or "CONFIDENTIAL".'),
42
+ pages: z
43
+ .union([z.array(z.number().int().positive()), z.string()])
44
+ .optional()
45
+ .describe('Pages to stamp, as [1,2] or "1-3,7". Omit for every page.'),
46
+ fontSize: z.number().positive().max(200).optional().describe("Defaults to 48."),
47
+ color: z.string().optional().describe('Hex RGB without "#". Defaults to "FF0000".'),
48
+ opacity: z.number().min(0.05).max(1).optional().describe("Defaults to 0.25."),
49
+ rotation: z.number().optional().describe("Degrees. Defaults to 45.")
50
+ }),
51
+ z.object({
52
+ op: z.literal("page_numbers"),
53
+ format: z
54
+ .string()
55
+ .optional()
56
+ .describe('Template using {page} and {total}, e.g. "Page {page} of {total}". Defaults to that.'),
57
+ startAt: z
58
+ .number()
59
+ .int()
60
+ .positive()
61
+ .optional()
62
+ .describe("Number to give the first page. Defaults to 1."),
63
+ fontSize: z.number().positive().max(72).optional().describe("Defaults to 9."),
64
+ position: z
65
+ .enum(["bottom-right", "bottom-center", "bottom-left"])
66
+ .optional()
67
+ .describe("Defaults to bottom-center.")
68
+ }),
69
+ z.object({
70
+ op: z.literal("stamp"),
71
+ text: z.string().min(1).describe("Text to place at a fixed position."),
72
+ x: z.number().describe("Points from the left edge."),
73
+ y: z.number().describe("Points from the BOTTOM edge — PDF coordinates start bottom-left."),
74
+ pages: z.union([z.array(z.number().int().positive()), z.string()]).optional(),
75
+ fontSize: z.number().positive().max(200).optional().describe("Defaults to 12."),
76
+ color: z.string().optional().describe('Hex RGB without "#". Defaults to "000000".')
77
+ }),
78
+ z.object({
79
+ op: z.literal("delete_pages"),
80
+ pages: z
81
+ .union([z.array(z.number().int().positive()), z.string()])
82
+ .describe('Pages to remove, e.g. "2,5-7".')
83
+ }),
84
+ z.object({
85
+ op: z.literal("keep_pages"),
86
+ pages: z
87
+ .union([z.array(z.number().int().positive()), z.string()])
88
+ .describe("Pages to keep; all others are removed.")
89
+ }),
90
+ z.object({
91
+ op: z.literal("rotate"),
92
+ degrees: z.union([z.literal(90), z.literal(180), z.literal(270)]),
93
+ pages: z
94
+ .union([z.array(z.number().int().positive()), z.string()])
95
+ .optional()
96
+ .describe("Set these pages' absolute rotation to 90, 180 or 270 degrees; it is not relative to their current rotation.")
97
+ }),
98
+ z.object({
99
+ op: z.literal("append"),
100
+ path: z.string().min(1).describe("Another PDF to append, relative to the server root."),
101
+ pages: z
102
+ .union([z.array(z.number().int().positive()), z.string()])
103
+ .optional()
104
+ .describe("Pages of that PDF to append. Omit for all of them.")
105
+ })
106
+ ]);
107
+ export const pdfEditTool = defineTool({
108
+ name: "pdf_edit",
109
+ group: "pdf",
110
+ title: "Edit an existing PDF",
111
+ description: "Apply operations to a PDF: watermark, page numbers, a positioned stamp, delete or keep pages, rotate, or append another PDF. Overlays are drawn over the original content, which is never rewritten. Use dryRun to see the effect described before writing. There is no text extraction into a new PDF and no PDF→Word.",
112
+ inputSchema: {
113
+ path: z.string().min(1).describe("PDF to edit, relative to the server root."),
114
+ ops: z.array(opSchema).min(1).describe("Operations, applied in order."),
115
+ out: z
116
+ .string()
117
+ .optional()
118
+ .describe("Write below @output/. Required for input files unless --allow-in-place is enabled."),
119
+ dryRun: z.boolean().optional().describe("Describe what would change without writing."),
120
+ backup: z
121
+ .boolean()
122
+ .optional()
123
+ .describe("When editing in place, copy the original to <name>.bak first. Defaults to true."),
124
+ overwrite: z.boolean().optional().describe("Replace an existing `out` file. Defaults to false.")
125
+ },
126
+ annotations: {
127
+ readOnlyHint: false,
128
+ destructiveHint: true,
129
+ idempotentHint: false,
130
+ openWorldHint: false
131
+ },
132
+ mutates: true,
133
+ handler: async (args, context) => {
134
+ const { config } = context;
135
+ assertWritable(config);
136
+ const resolved = await resolveInRoot(config, args.path, { mustExist: true });
137
+ await assertReadableSize(config, resolved, args.path);
138
+ const inputVersion = await fingerprint(resolved);
139
+ const bytes = new Uint8Array(await readFile(resolved));
140
+ const info = await Pdf.read(bytes, { extractText: false, extractImages: false }).catch((cause) => {
141
+ throw toolError.unsupported(`could not read ${args.path} as a PDF`, "A password-protected PDF cannot be edited here. Run doc_inspect to check the file type.", { cause });
142
+ });
143
+ const pageCount = info.metadata?.pageCount ?? 0;
144
+ if (pageCount === 0) {
145
+ throw toolError.unsupported(`${args.path} reports no pages`, "The file may be corrupt.");
146
+ }
147
+ if (pageCount > MAX_PAGES) {
148
+ throw toolError.tooLarge(`${args.path} has ${pageCount} pages, over the ${MAX_PAGES} limit`, "Split it first with a keep_pages operation on a copy.");
149
+ }
150
+ // Editor.load is synchronous despite the async surroundings.
151
+ let editor;
152
+ try {
153
+ editor = Pdf.Editor.load(bytes);
154
+ }
155
+ catch (cause) {
156
+ throw toolError.unsupported(`could not open ${args.path} for editing`, undefined, { cause });
157
+ }
158
+ // Page count changes as pages are removed, so it is tracked through the
159
+ // operation list rather than read once.
160
+ const pageMap = Array.from({ length: pageCount }, (_, index) => index);
161
+ const applied = [];
162
+ // Structural operations force a full rebuild; overlay-only edits do not.
163
+ const structural = args.ops.some(op => STRUCTURAL_OPS.has(op.op));
164
+ for (const [index, op] of args.ops.entries()) {
165
+ try {
166
+ const result = await applyOp(editor, op, pageMap, config);
167
+ applied.push(result.description);
168
+ }
169
+ catch (cause) {
170
+ if (cause instanceof Error && cause.name === "McpToolError") {
171
+ throw cause;
172
+ }
173
+ throw toolError.invalidInput(`op ${index + 1} (${op.op}) failed: ${cause instanceof Error ? cause.message : String(cause)}`, "Nothing was written.", { cause });
174
+ }
175
+ }
176
+ if (args.dryRun === true) {
177
+ return textResult(config, [
178
+ `**Dry run** — nothing was written to ${args.path}.`,
179
+ `- pages: ${pageCount} → ${pageMap.length}`,
180
+ "",
181
+ "Would apply:",
182
+ ...applied.map((line, index) => `${index + 1}. ${line}`),
183
+ "",
184
+ "Re-run without dryRun to write these changes."
185
+ ].join("\n"));
186
+ }
187
+ // `out` may name the very file being edited (`a.pdf` vs `./a.pdf`), so the
188
+ // decision is made on the resolved paths, not on whether `out` was given.
189
+ await assertUnchanged(resolved, inputVersion);
190
+ const writeTarget = await resolveEditTarget(config, args.path, args.out);
191
+ const target = writeTarget.path;
192
+ const inPlace = isSameFile(target, resolved);
193
+ const backupPath = inPlace && (args.backup ?? true) ? await backupOnce(writeTarget) : undefined;
194
+ // Overlay-only: prefer the incremental path so bookmarks, form fields and
195
+ // signatures survive. `saveIncremental` itself falls back to a rebuild for
196
+ // xref-stream files, so the report is based on what was actually possible.
197
+ const incrementalPossible = !structural && supportsIncrementalUpdate(bytes);
198
+ const out = incrementalPossible ? await editor.saveIncremental() : await editor.save();
199
+ if (inPlace) {
200
+ await writeFileAtomic(target, out);
201
+ }
202
+ else {
203
+ await writeBytesWithPolicy(target, args.overwrite === true, out);
204
+ }
205
+ // Re-read so the reported page count is the file's, not the editor's idea.
206
+ const verified = await Pdf.read(new Uint8Array(out), {
207
+ extractText: false,
208
+ extractImages: false
209
+ });
210
+ return textResult(config, [
211
+ `Edited **${args.path}** — ${applied.length} operation(s) applied.`,
212
+ `- written to ${writeTarget.display}${inPlace ? " (in place)" : ""} (${formatBytes(out.byteLength)})`,
213
+ `- pages: ${pageCount} → ${verified.metadata?.pageCount ?? pageMap.length}`,
214
+ incrementalPossible
215
+ ? "- saved as an incremental update: bookmarks, form fields and original signature bytes are preserved; a certified signature may still report the document as modified if its DocMDP permissions forbid this edit"
216
+ : structural
217
+ ? "- **structural change, so the file was rebuilt**: any signature is now invalid, and document-level extras such as bookmarks may not survive"
218
+ : "- rebuilt rather than appended (this PDF uses a cross-reference stream), so any signature is now invalid",
219
+ ...describeBackup(writeTarget.display, backupPath),
220
+ "",
221
+ ...applied.map((line, index) => `${index + 1}. ${line}`),
222
+ "",
223
+ "Read it back with doc_read to verify any text you added."
224
+ ].join("\n"));
225
+ }
226
+ });
227
+ async function applyOp(editor, op, pageMap, config) {
228
+ const pageCount = pageMap.length;
229
+ switch (op.op) {
230
+ case "watermark": {
231
+ const pages = resolvePages(op.pages, pageCount);
232
+ for (const page of pages) {
233
+ editor.getPage(requireOriginalPage(pageMap, page)).drawText(op.text, {
234
+ x: 120,
235
+ y: 360,
236
+ fontSize: op.fontSize ?? 48,
237
+ rotation: op.rotation ?? 45,
238
+ // Transparency is the colour's alpha channel; drawText has no
239
+ // separate opacity option.
240
+ color: toColor(op.color ?? "FF0000", op.opacity ?? 0.25)
241
+ });
242
+ }
243
+ return {
244
+ description: `watermarked ${pages.length} page(s) with ${JSON.stringify(op.text)}`
245
+ };
246
+ }
247
+ case "page_numbers": {
248
+ const template = op.format ?? "Page {page} of {total}";
249
+ const startAt = op.startAt ?? 1;
250
+ const fontSize = op.fontSize ?? 9;
251
+ const position = op.position ?? "bottom-center";
252
+ for (let index = 0; index < pageCount; index += 1) {
253
+ const label = template
254
+ .replace(/\{page\}/g, String(index + startAt))
255
+ .replace(/\{total\}/g, String(pageCount + startAt - 1));
256
+ editor.getPage(requireOriginalPage(pageMap, index + 1)).drawText(label, {
257
+ x: position === "bottom-left" ? 60 : position === "bottom-center" ? 260 : 460,
258
+ y: 28,
259
+ fontSize
260
+ });
261
+ }
262
+ return {
263
+ description: `numbered ${pageCount} page(s) as ${JSON.stringify(template)}`
264
+ };
265
+ }
266
+ case "stamp": {
267
+ const pages = resolvePages(op.pages, pageCount);
268
+ for (const page of pages) {
269
+ editor.getPage(requireOriginalPage(pageMap, page)).drawText(op.text, {
270
+ x: op.x,
271
+ y: op.y,
272
+ fontSize: op.fontSize ?? 12,
273
+ color: toColor(op.color ?? "000000")
274
+ });
275
+ }
276
+ return { description: `stamped ${pages.length} page(s) at (${op.x}, ${op.y})` };
277
+ }
278
+ case "delete_pages": {
279
+ const pages = resolvePages(op.pages, pageCount);
280
+ if (pages.length >= pageCount) {
281
+ throw toolError.invalidInput("that would delete every page", "A PDF must keep at least one page.");
282
+ }
283
+ // Descending, so each removal cannot shift the index of the next.
284
+ for (const page of [...pages].sort((a, b) => b - a)) {
285
+ const [original] = pageMap.splice(page - 1, 1);
286
+ if (original === undefined || original < 0) {
287
+ throw toolError.invalidInput("an appended page cannot be removed in the same call");
288
+ }
289
+ editor.removePage(original);
290
+ }
291
+ return {
292
+ description: `deleted page(s) ${pages.join(", ")}`
293
+ };
294
+ }
295
+ case "keep_pages": {
296
+ const keep = new Set(resolvePages(op.pages, pageCount));
297
+ if (keep.size === 0) {
298
+ throw toolError.invalidInput("keep_pages must keep at least one page");
299
+ }
300
+ const remove = [];
301
+ for (let page = 1; page <= pageCount; page += 1) {
302
+ if (!keep.has(page)) {
303
+ remove.push(page);
304
+ }
305
+ }
306
+ for (const page of remove.toSorted((a, b) => b - a)) {
307
+ const [original] = pageMap.splice(page - 1, 1);
308
+ if (original === undefined || original < 0) {
309
+ throw toolError.invalidInput("an appended page cannot be removed in the same call");
310
+ }
311
+ editor.removePage(original);
312
+ }
313
+ return {
314
+ description: `kept page(s) ${[...keep].toSorted((a, b) => a - b).join(", ")}, removed ${remove.length}`
315
+ };
316
+ }
317
+ case "rotate": {
318
+ const pages = resolvePages(op.pages, pageCount);
319
+ for (const page of pages) {
320
+ editor.rotatePage(requireOriginalPage(pageMap, page), op.degrees);
321
+ }
322
+ return { description: `set ${pages.length} page(s) to ${op.degrees}° rotation` };
323
+ }
324
+ case "append": {
325
+ const source = await resolveInRoot(config, op.path, { mustExist: true });
326
+ const sourceBytes = new Uint8Array(await readFile(source));
327
+ const sourceInfo = await Pdf.read(sourceBytes, {
328
+ extractText: false,
329
+ extractImages: false
330
+ }).catch((cause) => {
331
+ throw toolError.unsupported(`could not read ${op.path} as a PDF`, undefined, { cause });
332
+ });
333
+ const sourcePageCount = sourceInfo.metadata?.pageCount ?? 0;
334
+ const wanted = op.pages === undefined ? undefined : resolvePages(op.pages, sourcePageCount);
335
+ editor.copyPagesFrom(sourceBytes, wanted === undefined ? undefined : wanted.map(page => page - 1));
336
+ const added = wanted === undefined ? sourcePageCount : wanted.length;
337
+ // Copied pages are not addressable through getPage/removePage until the
338
+ // rebuilt document is loaded again. Keep sentinels so a later operation
339
+ // gets an honest error instead of silently touching an original page.
340
+ pageMap.push(...Array.from({ length: added }, () => -1));
341
+ return {
342
+ description: `appended ${added} page(s) from ${op.path}`
343
+ };
344
+ }
345
+ }
346
+ }
347
+ /** Original editor index corresponding to a current 1-based page number. */
348
+ function requireOriginalPage(pageMap, page) {
349
+ const original = pageMap[page - 1];
350
+ if (original === undefined) {
351
+ throw toolError.invalidInput(`page ${page} does not exist`);
352
+ }
353
+ if (original < 0) {
354
+ throw toolError.invalidInput(`page ${page} was appended earlier in this call and cannot be edited until the PDF is saved and reopened`, "Put append last, or make a second pdf_edit call for the appended pages.");
355
+ }
356
+ return original;
357
+ }
358
+ /** Resolve a page selector against the live page count, or every page. */
359
+ function resolvePages(selector, pageCount) {
360
+ const parsed = parsePages(selector);
361
+ if (parsed === undefined) {
362
+ return Array.from({ length: pageCount }, (_, index) => index + 1);
363
+ }
364
+ const outOfRange = parsed.filter(page => page > pageCount);
365
+ if (outOfRange.length > 0) {
366
+ throw toolError.invalidInput(`page(s) ${outOfRange.join(", ")} do not exist — the document has ${pageCount}`, "Check the page count with doc_read or doc_inspect first.");
367
+ }
368
+ return [...new Set(parsed)].toSorted((a, b) => a - b);
369
+ }
370
+ /**
371
+ * Convert `RRGGBB` to the engine's normalised colour.
372
+ *
373
+ * `PdfColor` components run 0–1, not 0–255, and its `a` channel is how
374
+ * transparency is expressed — passing a hex string type-checks nowhere and
375
+ * would be silently ignored.
376
+ */
377
+ function toColor(color, alpha) {
378
+ const hex = color.replace(/^#/, "").toUpperCase();
379
+ if (!/^[0-9A-F]{6}$/.test(hex)) {
380
+ throw toolError.invalidInput(`${JSON.stringify(color)} is not a hex colour`, 'Use RRGGBB, e.g. "FF0000".');
381
+ }
382
+ const channel = (offset) => Number.parseInt(hex.slice(offset, offset + 2), 16) / 255;
383
+ return {
384
+ r: channel(0),
385
+ g: channel(2),
386
+ b: channel(4),
387
+ ...(alpha === undefined ? {} : { a: alpha })
388
+ };
389
+ }
390
+ //# sourceMappingURL=pdf-edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf-edit.js","sourceRoot":"","sources":["../../src/tools/pdf-edit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Tool result helpers.
3
+ *
4
+ * Every tool returns text, not binary — a model cannot see an image and this
5
+ * toolkit has no PDF rasterizer, so a structured textual description is the
6
+ * only channel that exists. These helpers keep truncation honest: a silently
7
+ * cut-off table is worse than no table, because the model will reason over it
8
+ * as if it were complete.
9
+ */
10
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
11
+ import type { ServerConfig } from "../config.js";
12
+ /** A successful text result, truncated to the configured output budget. */
13
+ export declare function textResult(config: ServerConfig, text: string): CallToolResult;
14
+ /** An error result. The model reads this and decides whether to retry. */
15
+ export declare function errorResult(text: string): CallToolResult;
16
+ /**
17
+ * Cut `text` to the output budget, appending an explicit marker.
18
+ *
19
+ * The marker matters: it tells the model the data is incomplete so it asks for
20
+ * a narrower range instead of drawing conclusions from a partial document.
21
+ */
22
+ export declare function truncate(config: ServerConfig, text: string): string;
23
+ /** Render a byte count for humans, e.g. `1.4 MiB`. */
24
+ export declare function formatBytes(bytes: number): string;
25
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,CAE7E;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnE;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUjD"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Tool result helpers.
3
+ *
4
+ * Every tool returns text, not binary — a model cannot see an image and this
5
+ * toolkit has no PDF rasterizer, so a structured textual description is the
6
+ * only channel that exists. These helpers keep truncation honest: a silently
7
+ * cut-off table is worse than no table, because the model will reason over it
8
+ * as if it were complete.
9
+ */
10
+ /** A successful text result, truncated to the configured output budget. */
11
+ export function textResult(config, text) {
12
+ return { content: [{ type: "text", text: truncate(config, text) }] };
13
+ }
14
+ /** An error result. The model reads this and decides whether to retry. */
15
+ export function errorResult(text) {
16
+ return { isError: true, content: [{ type: "text", text }] };
17
+ }
18
+ /**
19
+ * Cut `text` to the output budget, appending an explicit marker.
20
+ *
21
+ * The marker matters: it tells the model the data is incomplete so it asks for
22
+ * a narrower range instead of drawing conclusions from a partial document.
23
+ */
24
+ export function truncate(config, text) {
25
+ if (text.length <= config.maxOutputChars) {
26
+ return text;
27
+ }
28
+ const omitted = text.length - config.maxOutputChars;
29
+ return `${text.slice(0, config.maxOutputChars)}\n\n[truncated: ${omitted} more characters. Request a narrower range or use pagination to see the rest.]`;
30
+ }
31
+ /** Render a byte count for humans, e.g. `1.4 MiB`. */
32
+ export function formatBytes(bytes) {
33
+ const units = ["B", "KiB", "MiB", "GiB"];
34
+ let value = bytes;
35
+ let unitIndex = 0;
36
+ while (value >= 1024 && unitIndex < units.length - 1) {
37
+ value /= 1024;
38
+ unitIndex += 1;
39
+ }
40
+ const unit = units[unitIndex] ?? "B";
41
+ return unitIndex === 0 ? `${bytes} ${unit}` : `${value.toFixed(1)} ${unit}`;
42
+ }
43
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,2EAA2E;AAC3E,MAAM,UAAU,UAAU,CAAC,MAAoB,EAAE,IAAY;IAC3D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAoB,EAAE,IAAY;IACzD,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;IACpD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,mBAAmB,OAAO,gFAAgF,CAAC;AAC3J,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;IAClD,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,KAAK,IAAI,IAAI,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,KAAK,IAAI,IAAI,CAAC;QACd,SAAS,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC;IACrC,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `sheet_edit` — patch an existing workbook in place.
3
+ *
4
+ * The counterpart to `sheet_write`: that one builds a file, this one changes a
5
+ * file someone already has. The distinction matters because the risky operation
6
+ * is the second — a user's real spreadsheet, whose other sheets, formatting and
7
+ * formulas must survive untouched.
8
+ *
9
+ * Two safeguards follow from that. Operations are applied to an in-memory copy
10
+ * and only written once every one of them has succeeded, so a bad op cannot
11
+ * leave a half-edited file. And `dryRun` reports what *would* change without
12
+ * writing, because a model's decision to edit is far likelier to be wrong than
13
+ * its ability to execute the edit.
14
+ */
15
+ export declare const sheetEditTool: import("./types.js").AnyToolDefinition;
16
+ //# sourceMappingURL=sheet-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheet-edit.d.ts","sourceRoot":"","sources":["../../src/tools/sheet-edit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAmGH,eAAO,MAAM,aAAa,wCA2IxB,CAAC"}