bantamkit-mcp 0.29.1 → 0.29.2

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/dist/docread.d.ts CHANGED
@@ -34,6 +34,7 @@
34
34
  * (`utf8Scan`).
35
35
  */
36
36
  import { BantamError } from './errors.js';
37
+ import { cmpCodepoint, pyRepr, pyStrip } from './pysem.js';
37
38
  export declare const NS_S = "{http://schemas.openxmlformats.org/spreadsheetml/2006/main}";
38
39
  export declare const NS_W = "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}";
39
40
  export declare const NS_R = "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}";
@@ -52,19 +53,15 @@ export declare const OMIT_UNMAPPED = "unmapped-text";
52
53
  export declare const OMIT_UNREAD_TAIL = "unread-tail";
53
54
  export declare const OMIT_SIZE_CAP = "size-cap";
54
55
  export declare const OMIT_UNPLACED_CELL = "unplaced-cell";
56
+ export declare const OMIT_DUPLICATE_CELL = "duplicate-cell";
55
57
  /** Extraction failed. The message names what was seen, never just the format's own error. */
56
58
  export declare class DocumentReadError extends BantamError {
57
59
  }
58
- /** `str.strip()` with no argument. */
59
- export declare function pyStrip(s: string): string;
60
+ export { cmpCodepoint, pyRepr, pyStrip };
60
61
  /** `str.split()` with no argument: runs of whitespace, no empty fields. */
61
62
  export declare function pySplit(s: string): string[];
62
63
  /** `str.splitlines()`: Python's line boundaries, terminators dropped. */
63
64
  export declare function pySplitlines(s: string): string[];
64
- /** `sorted()` on strings: by code point, which is not what `Array.sort` does above U+FFFF. */
65
- export declare function cmpCodepoint(a: string, b: string): number;
66
- /** `repr(str)`. */
67
- export declare function pyRepr(s: string): string;
68
65
  /** `repr(bytes)`. */
69
66
  export declare function bytesRepr(buf: Uint8Array): string;
70
67
  export interface Utf8Scan {
@@ -190,6 +187,35 @@ export declare class BadZipFile extends Error {
190
187
  constructor(message: string);
191
188
  }
192
189
  export declare function crc32(buf: Uint8Array): number;
190
+ /**
191
+ * How much ONE MEMBER of a zip this reader will decompress and parse. The ceiling on the
192
+ * PARSE, which is a different door from `XLSX_MAX_TEXT_BYTES`: that one bounds the text a
193
+ * workbook renders, and it never stands in front of this, because `readMember` decompresses
194
+ * the member whole and `parsePart` builds a tree from it before the first row is rendered.
195
+ *
196
+ * MEASURED 2026-09-06 on this machine, through `docread.extract` on THIS runtime at the
197
+ * shipped constants, on a sheet of N `<row><c t="inlineStr"><is><t>x</t></is></c></row>`
198
+ * deflated by `deflateRawSync`, peak RSS from `process.resourceUsage().maxRSS`:
199
+ * 400,000 rows are 58,378 bytes on disk, declare 19,600,112, and took RSS from 102.2 MB to
200
+ * 1,039.3 MB in 1,019 ms with NO omission; 1,000,000 rows are 143,939 bytes, declare
201
+ * 49,000,112, and took it from 158.6 MB to 2,290.8 MB in 2,667 ms. Linear and unbounded —
202
+ * the memory is the `XmlElement` tree, not the text, so a budget over the rendering could
203
+ * not see it. The reference measured the same shape at 342.2 MB and 838.8 MB through
204
+ * `tracemalloc`; the numbers are not comparable (one counts a Python allocator, the other a
205
+ * whole process) and the SHAPE is what both of them state.
206
+ *
207
+ * 16 MiB, the number `TEXT_MAX_BYTES` states, because "how much of a file this reader reads"
208
+ * is one number — but under its OWN NAME, because it bounds a member of a container and not a
209
+ * file on a disk, and a bar that varies one must not be varying the other. The reference
210
+ * measured the corpus behind the figure: 25 OOXML/ODF packages under the goal's roots, the
211
+ * largest single XML member among them 4,283,286 bytes, 3.9x under this.
212
+ *
213
+ * A REFUSAL and not a truncation, which is the one place this module departs from
214
+ * "disclose, never truncate": half an XML document is not a smaller XML document, and a tree
215
+ * built from a severed member would carry text that is not what the file says. So the reader
216
+ * stops and names the member, the number the file declares and its own ceiling.
217
+ */
218
+ export declare const ZIP_MEMBER_MAX_BYTES: number;
193
219
  /** `zipfile.ZipFile` read-only: the central directory, and `read(name)` with a CRC check. */
194
220
  export declare class ZipReader {
195
221
  private readonly data;
@@ -209,6 +235,8 @@ export declare class ZipReader {
209
235
  isDir: boolean;
210
236
  }[];
211
237
  has(name: string): boolean;
238
+ /** `getinfo(name).file_size`: what the central directory DECLARES, before any inflate. */
239
+ declaredSize(name: string): number;
212
240
  /** `ZipFile.read(name)`; a missing member is a `KeyError` — here `RangeError`, see `readMember`. */
213
241
  read(name: string): Buffer;
214
242
  }
@@ -293,6 +321,32 @@ export declare const XLSX_MAX_COLUMNS = 16384;
293
321
  */
294
322
  export declare const UNPLACED_SHAPE = "the column of a cell whose reference is not letters then digits";
295
323
  export declare const UNPLACED_RANGE = "the column of a cell past XFD, the last column the format has";
324
+ export declare const DUPLICATE_CELL = "the text of a cell a later cell in the same row and column replaced";
325
+ /**
326
+ * How much text ONE WORKBOOK may materialise, all sheets together. `XLSX_MAX_COLUMNS` bounds a
327
+ * ROW and nothing bounded the document, which is a ceiling with a hole in it: the width is
328
+ * bought a row at a time. MEASURED 2026-09-06 on both runtimes: 20,000 rows each holding one
329
+ * `XFD1` cell deflate to 53,967 bytes and materialise 327,680,000 bytes in ~9 s — 6,072x, out
330
+ * of a file small enough to mail.
331
+ *
332
+ * 16 MiB, the same figure `TEXT_MAX_BYTES` carries and for the same kind of reason, but under
333
+ * its OWN NAME because the two bound different things: bytes read off a disk there, bytes
334
+ * rendered out of a container here, and a bar that varies one must not be varying the other.
335
+ * MEASURED 2026-09-06 over the goal's roots: 15 `.xlsx`, the largest 8,664,227 bytes on disk,
336
+ * and the largest RENDERING among them 754,520 bytes — 22x under this budget, so no real
337
+ * workbook on this machine meets it.
338
+ *
339
+ * It bounds the RENDERING and nothing else. The sentence that stood here said it bounded the
340
+ * rendering "because the file is already bounded", and that was FALSE for the whole life of
341
+ * this constant: `readMember` decompressed a member whole and `parsePart` built a tree from
342
+ * it, both before the first row was rendered and both outside this budget, so 58,378 bytes on
343
+ * disk took RSS to 1,039.3 MB with no omission and this ceiling never saw it (review round 5,
344
+ * H1). What bounds the file is `ZIP_MEMBER_MAX_BYTES`, one door earlier; this bounds what
345
+ * comes out of it. The shortfall is disclosed as `OMIT_SIZE_CAP` counting the rows no sheet
346
+ * rendered: a row is what a caller addresses, and a byte count of text that was never built
347
+ * would be a number this reader cannot honestly produce.
348
+ */
349
+ export declare const XLSX_MAX_TEXT_BYTES: number;
296
350
  /**
297
351
  * `B7` -> `[1, '']`. The cell's own reference decides its column; XML order is a fallback.
298
352
  *
@@ -320,8 +374,22 @@ export declare const UNPLACED_RANGE = "the column of a cell past XFD, the last c
320
374
  * spends asking for more.
321
375
  */
322
376
  export declare function columnIndex(ref: string | undefined, fallback: number): [number, string];
323
- export declare function extractXlsx(path: string): Document;
324
- export declare function extractDocx(path: string): Document;
377
+ /**
378
+ * Every declared sheet, under ONE `XLSX_MAX_TEXT_BYTES` budget for the whole workbook.
379
+ *
380
+ * The budget is the document's, so it is made here and not in `sheetRows`, and the shortfall
381
+ * is disclosed at the document's grain for the same reason — it is not a fact about the sheet
382
+ * the budget happened to run out on. The cap is stated BEFORE the media tally, because the
383
+ * media a reader met is a count of what it met underneath the cap.
384
+ *
385
+ * `opened` is the reader `sniff` already had to build to decide this file is an OOXML package
386
+ * (entries (a)/(j)): before it was handed down, one `extract` read the whole archive off disk
387
+ * TWICE. It is a parameter and never a field, so its lifetime is this call — a reader kept
388
+ * across calls would answer from bytes no longer on disk, which is exactly what the document
389
+ * cache one layer up is keyed on (realpath, size, mtime_ns) to avoid.
390
+ */
391
+ export declare function extractXlsx(path: string, opened?: ZipReader | null): Document;
392
+ export declare function extractDocx(path: string, opened?: ZipReader | null): Document;
325
393
  /** `html.unescape`. */
326
394
  export declare function unescape(s: string): string;
327
395
  /** Rendered rows of one HTML fragment. A pure function of the string: no I/O, no host. */
@@ -349,6 +417,12 @@ export declare function a2bUu(line: Uint8Array): Buffer;
349
417
  */
350
418
  export declare function decodeUu(encoded: Buffer): Buffer;
351
419
  export declare function extractMhtml(path: string): Document;
420
+ /**
421
+ * Markup to rows, up to `TEXT_MAX_BYTES` of it, saying how much it did not read.
422
+ *
423
+ * BOUNDED, entry (k): this did `readFileSync(path)`, so a 1 GB `.html` was materialised whole
424
+ * where a 1 GB `.txt` had stopped at the cap and counted the rest since J10.
425
+ */
352
426
  export declare function extractHtml(path: string): Document;
353
427
  export declare function extractText(path: string): Document;
354
428
  /** Dispatch on what the file IS. Anything unreadable raises, naming the container. */