@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,463 @@
1
+ /**
2
+ * `doc_inspect` — the cheap first call.
3
+ *
4
+ * Every other tool is expensive in context: reading a sheet or a document body
5
+ * spends thousands of tokens. This one spends a few dozen and answers the
6
+ * questions that stop the model guessing — what kind of file is this, how big,
7
+ * and for CSV, which delimiter and line ending is it actually using.
8
+ *
9
+ * The CSV dialect fields are why this tool imports from the core package: a
10
+ * model has no way to know that a "csv" is semicolon-separated with a BOM,
11
+ * and getting it wrong silently produces a one-column table.
12
+ */
13
+ import fs from "node:fs/promises";
14
+ import path from "node:path";
15
+ import { ArchiveFile } from "documonster/archive";
16
+ import { Csv } from "documonster/csv";
17
+ import { Workbook } from "documonster/excel";
18
+ import { Pdf } from "documonster/pdf";
19
+ import { Io, Layout, Query, Template } from "documonster/word";
20
+ import { z } from "zod";
21
+ import { toolError } from "../errors.js";
22
+ import { resolveInRoot } from "../sandbox.js";
23
+ import { formatBytes, textResult } from "./result.js";
24
+ import { describeWindow, sheetName, usedWindow } from "./spreadsheet.js";
25
+ import { defineTool } from "./types.js";
26
+ /** Bytes read from the head of a text file for dialect detection. */
27
+ const HEAD_SAMPLE_BYTES = 64 * 1024;
28
+ /** Maximum directory entries listed in one call. */
29
+ const MAX_DIR_ENTRIES = 200;
30
+ export const inspectTool = defineTool({
31
+ name: "doc_inspect",
32
+ group: "core",
33
+ title: "Inspect a document or directory",
34
+ description: "Identify a file (type, size, and for CSV its delimiter/line-ending/BOM) or list a directory. Always call this before reading a document: it is cheap and prevents guessing the wrong format, sheet or column.",
35
+ inputSchema: {
36
+ path: z
37
+ .string()
38
+ .min(1)
39
+ .describe("File or directory path, relative to the server root. Use '.' for the root itself.")
40
+ },
41
+ annotations: { readOnlyHint: true, openWorldHint: false },
42
+ mutates: false,
43
+ handler: async (args, context) => {
44
+ const { config } = context;
45
+ const resolved = await resolveInRoot(config, args.path, { mustExist: true });
46
+ const stats = await fs.stat(resolved);
47
+ const displayPath = toDisplayPath(config.root, resolved);
48
+ if (stats.isDirectory()) {
49
+ return textResult(config, await describeDirectory(resolved, displayPath));
50
+ }
51
+ if (!stats.isFile()) {
52
+ throw toolError.unsupported(`not a regular file or directory: ${args.path}`, "Only files and directories can be inspected.");
53
+ }
54
+ return textResult(config, await describeFile(config, resolved, displayPath, stats.size, stats.mtime));
55
+ }
56
+ });
57
+ async function describeDirectory(resolved, displayPath) {
58
+ const entries = await fs.readdir(resolved, { withFileTypes: true });
59
+ const sorted = entries.toSorted((a, b) => a.name.localeCompare(b.name));
60
+ const shown = sorted.slice(0, MAX_DIR_ENTRIES);
61
+ // stat every shown entry so the model can judge what is worth reading, in
62
+ // parallel — serial awaits would cost up to MAX_DIR_ENTRIES round trips. A
63
+ // failure on one entry (broken symlink, concurrent delete) must not fail the
64
+ // whole listing, so each result is settled independently.
65
+ const sizes = await Promise.all(shown.map(async (entry) => {
66
+ if (entry.isDirectory()) {
67
+ return undefined;
68
+ }
69
+ try {
70
+ const stats = await fs.stat(path.join(resolved, entry.name));
71
+ return formatBytes(stats.size);
72
+ }
73
+ catch {
74
+ return "(unreadable)";
75
+ }
76
+ }));
77
+ const lines = [`# Directory: ${displayPath}`, "", `${entries.length} entries`, ""];
78
+ for (const [index, entry] of shown.entries()) {
79
+ if (entry.isDirectory()) {
80
+ lines.push(`- \`${entry.name}/\``);
81
+ continue;
82
+ }
83
+ const size = sizes[index];
84
+ lines.push(`- \`${entry.name}\`${size === undefined ? "" : ` — ${size}`}`);
85
+ }
86
+ if (sorted.length > shown.length) {
87
+ lines.push("", `[${sorted.length - shown.length} more entries not listed]`);
88
+ }
89
+ return lines.join("\n");
90
+ }
91
+ async function describeFile(config, resolved, displayPath, size, modified) {
92
+ const head = await readHead(resolved, HEAD_SAMPLE_BYTES);
93
+ const kind = await detectKind(resolved, head);
94
+ const lines = [
95
+ `# File: ${displayPath}`,
96
+ "",
97
+ `- kind: **${kind}**`,
98
+ `- size: ${formatBytes(size)} (${size} bytes)`,
99
+ `- modified: ${modified.toISOString()}`
100
+ ];
101
+ if (size > config.maxFileSize) {
102
+ lines.push(`- **over the server's ${formatBytes(config.maxFileSize)} size limit** — reading it will be rejected`);
103
+ }
104
+ const detail = await describeKind(kind, head, resolved, config);
105
+ if (detail.length > 0) {
106
+ lines.push("", ...detail);
107
+ }
108
+ const mismatch = describeExtensionMismatch(resolved, kind);
109
+ if (mismatch.length > 0) {
110
+ lines.push("", ...mismatch);
111
+ }
112
+ return lines.join("\n");
113
+ }
114
+ /**
115
+ * Warn when the extension claims a format the bytes contradict.
116
+ *
117
+ * This is the payoff for checking magic bytes first. A `.xlsx` that is really a
118
+ * CSV is routine in exported data, and left unflagged the model would confidently
119
+ * hand it to a spreadsheet reader and misread the resulting failure.
120
+ */
121
+ function describeExtensionMismatch(filePath, kind) {
122
+ const claimed = CLAIMED_BY_EXTENSION[path.extname(filePath).toLowerCase()];
123
+ if (claimed === undefined || claimed === kind) {
124
+ return [];
125
+ }
126
+ return [
127
+ `**Extension mismatch**: the name claims \`${claimed}\` but the content is not that format (detected: \`${kind}\`).`,
128
+ "Trust the detected kind, not the extension, and tell the user about the discrepancy."
129
+ ];
130
+ }
131
+ /** Formats an extension asserts, for cross-checking against detected content. */
132
+ const CLAIMED_BY_EXTENSION = {
133
+ ".xlsx": "excel",
134
+ ".xlsm": "excel",
135
+ ".xltx": "excel",
136
+ ".docx": "word",
137
+ ".docm": "word",
138
+ ".dotx": "word",
139
+ ".pptx": "powerpoint",
140
+ ".pdf": "pdf",
141
+ ".zip": "zip"
142
+ };
143
+ /** Per-kind extra facts worth knowing before reading. */
144
+ async function describeKind(kind, head, resolved, config) {
145
+ switch (kind) {
146
+ case "csv":
147
+ return describeCsv(head);
148
+ case "excel":
149
+ return await describeWorkbook(resolved, config);
150
+ case "word":
151
+ return await describeWordDocument(resolved, config);
152
+ case "pdf":
153
+ return await describePdf(resolved, config);
154
+ case "powerpoint":
155
+ return [
156
+ "This is a PowerPoint package. No tool reads .pptx — say so rather than guessing at its",
157
+ "contents."
158
+ ];
159
+ case "cfb":
160
+ return [
161
+ "This is a CFB/OLE2 container. That means either a legacy binary Office file (.doc/.xls,",
162
+ "which this toolkit does not read) or a password-encrypted OOXML document (which it does,",
163
+ "given the password). Ask the user which, rather than guessing."
164
+ ];
165
+ default:
166
+ return [];
167
+ }
168
+ }
169
+ /**
170
+ * List a workbook's sheets with their used ranges.
171
+ *
172
+ * This is what makes "always inspect first" pay for itself: the model learns
173
+ * the sheet names and roughly how much data each holds, so its next call names a
174
+ * real sheet and a sensible range instead of guessing and retrying.
175
+ *
176
+ * Opening the package costs the same parse a `sheet_read` would pay, so it is
177
+ * skipped for files over the configured size limit — where reading is refused
178
+ * anyway.
179
+ */
180
+ async function describeWorkbook(resolved, config) {
181
+ const stats = await fs.stat(resolved);
182
+ if (stats.size > config.maxFileSize) {
183
+ return [
184
+ "This is an Excel workbook, but it is over the size limit, so its sheets were not listed."
185
+ ];
186
+ }
187
+ const wb = Workbook.create();
188
+ try {
189
+ await Workbook.readFile(wb, resolved);
190
+ }
191
+ catch (cause) {
192
+ return [
193
+ `This looks like an Excel workbook but could not be parsed: ${cause instanceof Error ? cause.message : String(cause)}`,
194
+ "It may be corrupt, or password-protected."
195
+ ];
196
+ }
197
+ const sheets = Workbook.getWorksheets(wb);
198
+ if (sheets.length === 0) {
199
+ // A valid .xlsx always has at least one sheet, and a ZIP that merely looks
200
+ // like one parses without error into an empty workbook — so report the
201
+ // likely cause rather than the literal finding.
202
+ return [
203
+ "No worksheets were found. A valid Excel workbook always has at least one, so this is most",
204
+ "likely a ZIP file that is not really an .xlsx. Treat the extension as unreliable."
205
+ ];
206
+ }
207
+ const lines = [
208
+ "## Sheets",
209
+ "",
210
+ "| sheet | used range | rows | cols |",
211
+ "| --- | --- | --- | --- |"
212
+ ];
213
+ for (const ws of sheets) {
214
+ const window = usedWindow(ws);
215
+ lines.push(window === undefined
216
+ ? `| \`${sheetName(ws)}\` | (empty) | 0 | 0 |`
217
+ : `| \`${sheetName(ws)}\` | ${describeWindow(window)} | ${window.bottom - window.top + 1} | ${window.right - window.left + 1} |`);
218
+ }
219
+ lines.push("", "Read one with `sheet_read`, naming the sheet and a range.");
220
+ return lines;
221
+ }
222
+ /**
223
+ * Describe a Word document, and point at the right tool for it.
224
+ *
225
+ * The routing matters more than the statistics. A `.docx` may be prose, a
226
+ * `{{placeholder}}` template, or a form with legacy fields, and each wants a
227
+ * different tool — `doc_edit`, `template_fill`, `form_fill`. A model that cannot
228
+ * tell them apart reaches for the wrong one and then thrashes, so the answer is
229
+ * given here, in the call the model already makes first.
230
+ */
231
+ async function describeWordDocument(resolved, config) {
232
+ const stats = await fs.stat(resolved);
233
+ if (stats.size > config.maxFileSize) {
234
+ return ["This is a Word document, but it is over the size limit, so it was not opened."];
235
+ }
236
+ let doc;
237
+ try {
238
+ doc = await Io.readFile(resolved);
239
+ }
240
+ catch (cause) {
241
+ return [
242
+ `This looks like a Word document but could not be parsed: ${cause instanceof Error ? cause.message : String(cause)}`,
243
+ "It may be corrupt, or password-protected — neither can be read here."
244
+ ];
245
+ }
246
+ const headings = Query.getHeadings(doc);
247
+ const templateTags = Template.listTemplateTags(doc);
248
+ const formFields = Query.extractFormFields(doc);
249
+ const revisions = Query.listRevisions(doc);
250
+ const lines = [
251
+ "## Word document",
252
+ "",
253
+ `- pages: ${Layout.document(doc).pageCount} (computed, no Word needed)`,
254
+ `- paragraphs: ${Query.paragraphCount(doc)} · words: ${Query.countWords(doc)}`,
255
+ `- tables: ${Query.tableCount(doc)} · images: ${Query.listImages(doc).length}`,
256
+ `- headings: ${headings.length}`
257
+ ];
258
+ if (headings.length > 0) {
259
+ lines.push("", "Outline:", ...headings
260
+ .slice(0, 20)
261
+ .map(heading => `${" ".repeat(Math.max(0, heading.level - 1))}- H${heading.level}: ${heading.text}`), ...(headings.length > 20 ? [` … ${headings.length - 20} more`] : []));
262
+ }
263
+ // The routing advice. Each branch names one tool, because naming two invites
264
+ // the model to try both.
265
+ const routes = [];
266
+ if (templateTags.length > 0) {
267
+ routes.push(`- **This is a template**: ${templateTags.length} \`{{placeholder}}\` tag(s). Use \`template_inspect\` then \`template_fill\` — not doc_edit.`);
268
+ }
269
+ if (formFields.length > 0) {
270
+ routes.push(`- **This is a form**: ${formFields.length} fillable field(s). Use \`form_fill\` — not doc_edit.`);
271
+ }
272
+ if (revisions.length > 0) {
273
+ routes.push(`- **Contains ${revisions.length} tracked change(s).** Use \`doc_review\` to list, accept or reject them.`);
274
+ }
275
+ if (routes.length === 0) {
276
+ routes.push("- Ordinary prose. Read it with `doc_read`, change text with `doc_edit`.");
277
+ }
278
+ return [...lines, "", ...routes];
279
+ }
280
+ /**
281
+ * Describe a PDF, including whether there is any text to read at all.
282
+ *
283
+ * The scanned-document case is the one worth catching early: there is no OCR
284
+ * here, so a page image yields nothing, and a model told only "this is a PDF"
285
+ * will read it, get an empty result, and start inventing.
286
+ */
287
+ async function describePdf(resolved, config) {
288
+ const stats = await fs.stat(resolved);
289
+ if (stats.size > config.maxFileSize) {
290
+ return ["This is a PDF, but it is over the size limit, so it was not opened."];
291
+ }
292
+ const bytes = await fs.readFile(resolved);
293
+ let result;
294
+ try {
295
+ result = await Pdf.read(new Uint8Array(bytes), {
296
+ extractText: true,
297
+ extractImages: false,
298
+ extractTables: false,
299
+ extractAnnotations: false,
300
+ extractFormFields: true,
301
+ extractBookmarks: true
302
+ });
303
+ }
304
+ catch (cause) {
305
+ return [
306
+ `This looks like a PDF but could not be parsed: ${cause instanceof Error ? cause.message : String(cause)}`,
307
+ "It may be corrupt, or password-protected — a password cannot be supplied here."
308
+ ];
309
+ }
310
+ const pageCount = result.metadata?.pageCount ?? result.pages.length;
311
+ const emptyPages = result.pages.filter(page => page.text.trim().length === 0).length;
312
+ const formFields = result.formFields ?? [];
313
+ const lines = [
314
+ "## PDF",
315
+ "",
316
+ `- pages: ${pageCount}`,
317
+ `- PDF version: ${result.metadata?.pdfVersion ?? "unknown"}${result.metadata?.encrypted ? " · **encrypted**" : ""}`
318
+ ];
319
+ if (result.metadata?.title !== undefined && result.metadata.title.length > 0) {
320
+ lines.push(`- title: ${result.metadata.title}`);
321
+ }
322
+ if ((result.bookmarks?.length ?? 0) > 0) {
323
+ lines.push(`- bookmarks: ${result.bookmarks?.length}`);
324
+ }
325
+ if (formFields.length > 0) {
326
+ lines.push("", `- **This is a fillable form**: ${formFields.length} AcroForm field(s). Use \`form_fill\`.`);
327
+ }
328
+ if (emptyPages === pageCount) {
329
+ lines.push("", "- **No page yields any extractable text.** This is almost certainly a scan. There is no OCR", " here, so its contents cannot be read — say so rather than inferring them.", " You can still watermark, reorder or split it with `pdf_edit`.");
330
+ }
331
+ else if (emptyPages > 0) {
332
+ lines.push("", `- ${emptyPages} of ${pageCount} page(s) yield no text — probably scanned pages.`);
333
+ }
334
+ else {
335
+ lines.push("", "- Text is extractable on every page. Read it with `doc_read`.");
336
+ }
337
+ return lines;
338
+ }
339
+ /** Report the CSV dialect so the model does not have to guess it. */
340
+ function describeCsv(head) {
341
+ // `ignoreBOM: true` is required, despite reading backwards: it means "treat a
342
+ // leading U+FEFF as an ordinary character" rather than silently consuming it.
343
+ // Without it the BOM never reaches the string and we would always report
344
+ // "no BOM" — which is the one thing a caller most needs to know, because a
345
+ // stray BOM corrupts the first column's header.
346
+ const raw = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true }).decode(head);
347
+ const hasBom = raw.charCodeAt(0) === 0xfeff;
348
+ const text = Csv.stripBom(raw);
349
+ const delimiter = Csv.detectDelimiter(text);
350
+ const linebreak = Csv.detectLinebreak(text);
351
+ const firstLine = text.split(/\r\n|\r|\n/, 1)[0] ?? "";
352
+ const columns = firstLine.length > 0 ? firstLine.split(delimiter).length : 0;
353
+ return [
354
+ "## CSV dialect (detected from the first 64 KiB)",
355
+ "",
356
+ `- delimiter: \`${describeChar(delimiter)}\``,
357
+ `- line ending: \`${describeChar(linebreak)}\``,
358
+ `- UTF-8 BOM: ${hasBom ? "yes" : "no"}`,
359
+ `- columns in first line: ${columns}`,
360
+ "",
361
+ "Note: character-set detection is not implemented yet. A non-UTF-8 file (for example GBK from",
362
+ "a Chinese Windows export) will decode incorrectly — if the text below looks like mojibake, say",
363
+ "so instead of interpreting it.",
364
+ "",
365
+ "First line:",
366
+ "",
367
+ "```",
368
+ firstLine.slice(0, 500),
369
+ "```"
370
+ ];
371
+ }
372
+ function describeChar(value) {
373
+ return value.replace(/\t/g, "\\t").replace(/\r/g, "\\r").replace(/\n/g, "\\n");
374
+ }
375
+ /**
376
+ * Identify the file from its magic bytes, falling back to its extension.
377
+ *
378
+ * Magic bytes come first because extensions lie — a `.xlsx` that is really a
379
+ * CSV is a routine occurrence in exported data.
380
+ */
381
+ async function detectKind(filePath, head) {
382
+ if (startsWith(head, [0x50, 0x4b, 0x03, 0x04]) || startsWith(head, [0x50, 0x4b, 0x05, 0x06])) {
383
+ return await zipContentKind(filePath);
384
+ }
385
+ if (startsWith(head, [0x25, 0x50, 0x44, 0x46, 0x2d])) {
386
+ return "pdf";
387
+ }
388
+ if (startsWith(head, [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1])) {
389
+ return "cfb";
390
+ }
391
+ if (startsWith(head, [0x1f, 0x8b])) {
392
+ return "tar";
393
+ }
394
+ return textKindFromExtension(filePath);
395
+ }
396
+ /** Identify OOXML by the parts in the ZIP, never by the filename. */
397
+ async function zipContentKind(filePath) {
398
+ try {
399
+ const archive = await ArchiveFile.fromFile(filePath);
400
+ const names = new Set((await archive.getEntries()).map(entry => entry.path));
401
+ if (names.has("xl/workbook.xml")) {
402
+ return "excel";
403
+ }
404
+ if (names.has("word/document.xml")) {
405
+ return "word";
406
+ }
407
+ if (names.has("ppt/presentation.xml")) {
408
+ return "powerpoint";
409
+ }
410
+ }
411
+ catch {
412
+ // A malformed ZIP is still best described as ZIP; the archive tool will
413
+ // provide the parse failure if the caller tries to open it.
414
+ }
415
+ return "zip";
416
+ }
417
+ function textKindFromExtension(filePath) {
418
+ switch (path.extname(filePath).toLowerCase()) {
419
+ case ".csv":
420
+ case ".tsv":
421
+ return "csv";
422
+ case ".md":
423
+ case ".markdown":
424
+ return "markdown";
425
+ case ".xml":
426
+ return "xml";
427
+ case ".tar":
428
+ return "tar";
429
+ case ".txt":
430
+ case ".json":
431
+ case ".log":
432
+ return "text";
433
+ default:
434
+ return "unknown";
435
+ }
436
+ }
437
+ function startsWith(bytes, prefix) {
438
+ if (bytes.length < prefix.length) {
439
+ return false;
440
+ }
441
+ return prefix.every((byte, index) => bytes[index] === byte);
442
+ }
443
+ /** Read at most `limit` bytes from the head of a file. */
444
+ async function readHead(filePath, limit) {
445
+ const handle = await fs.open(filePath, "r");
446
+ try {
447
+ const buffer = new Uint8Array(limit);
448
+ const { bytesRead } = await handle.read(buffer, 0, limit, 0);
449
+ // A fixed byte count can split a multi-byte UTF-8 sequence at the tail;
450
+ // decoding is non-fatal, so that becomes one replacement character at the
451
+ // very end of a 64 KiB sample and cannot affect dialect detection.
452
+ return buffer.subarray(0, bytesRead);
453
+ }
454
+ finally {
455
+ await handle.close();
456
+ }
457
+ }
458
+ /** Render a path relative to the sandbox root, so the root itself never leaks. */
459
+ function toDisplayPath(root, resolved) {
460
+ const relative = path.relative(root, resolved);
461
+ return relative.length === 0 ? "." : relative;
462
+ }
463
+ //# sourceMappingURL=inspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/tools/inspect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
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
+ export declare const pdfEditTool: import("./types.js").AnyToolDefinition;
26
+ //# sourceMappingURL=pdf-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf-edit.d.ts","sourceRoot":"","sources":["../../src/tools/pdf-edit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAwGH,eAAO,MAAM,WAAW,wCAsJtB,CAAC"}