document-operations 1.1.50 → 1.1.52

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/index.cjs CHANGED
@@ -11,13 +11,13 @@ let document_outline_js = require("document-outline.js");
11
11
  /**
12
12
  * Builds a DocumentOperation whose input and output types are both inferred from real Zod schemas, so a call site never has to repeat `z.infer<typeof Schema>` itself. Use `defineOperationWithoutOutputSchema` instead for the rare operation whose original MCP tool registration declared no outputSchema at all.
13
13
  *
14
- * Deliberately returns the parameter object's own inferred literal type rather than an explicit `DocumentOperation<...>` return annotation. Zod 4's ZodType carries its own output type as one of three generic parameters (ZodType<Output, Input, Internals>), and TypeScript cannot prove, from inside this function body, that a generic `InputSchema extends z.ZodType` also extends `z.ZodType<z.infer<InputSchema>>` -- the two-step indirection through an abstract type parameter defeats it even though it is true for every concrete schema. Letting the literal's own type flow out instead sidesteps that: a caller's own concrete schema (e.g. `ConvertDocumentInputSchema`) is trivially assignable to `DocumentOperation<In, Out>`'s `z.ZodType<In>` field wherever that supertype is actually needed (the registry array below, or a future MCP/REST/CLI adapter parameter), because widening a CONCRETE schema's output type to line up is a normal covariant check, not the same self-referential generic one.
14
+ * Deliberately returns the parameter object's own inferred literal type rather than an explicit `DocumentOperation<...>` return annotation. Zod 4's ZodType carries its own output type as one of three generic parameters (ZodType<Output, Input, Internals>), and TypeScript cannot prove, from inside this function body, that a generic `InputSchema extends z.ZodType` also extends `z.ZodType<z.infer<InputSchema>>` — the two-step indirection through an abstract type parameter defeats it even though it is true for every concrete schema. Letting the literal's own type flow out instead sidesteps that: a caller's own concrete schema (e.g. `ConvertDocumentInputSchema`) is trivially assignable to `DocumentOperation<In, Out>`'s `z.ZodType<In>` field wherever that supertype is actually needed (the registry array below, or a future MCP/REST/CLI adapter parameter), because widening a CONCRETE schema's output type to line up is a normal covariant check, not the same self-referential generic one.
15
15
  */
16
16
  function defineOperation(operation) {
17
17
  return operation;
18
18
  }
19
19
  /**
20
- * The `defineOperation` counterpart for an operation with no output schema to infer from (the original MCP tool registration declared none) -- `Out` is inferred from `run`'s own return type instead. See `defineOperation`'s own comment for why this returns the parameter object's inferred literal type rather than an explicit `DocumentOperation<...>` annotation.
20
+ * The `defineOperation` counterpart for an operation with no output schema to infer from (the original MCP tool registration declared none) — `Out` is inferred from `run`'s own return type instead. See `defineOperation`'s own comment for why this returns the parameter object's inferred literal type rather than an explicit `DocumentOperation<...>` annotation.
21
21
  */
22
22
  function defineOperationWithoutOutputSchema(operation) {
23
23
  return operation;
@@ -68,7 +68,7 @@ function inferFormatFromExtension(path) {
68
68
  */
69
69
  const DocumentInputSchema = zod.z.union([zod.z.object({ path: zod.z.string().describe("Filesystem path to the document to read. The document format is inferred from the file extension.") }), zod.z.object({
70
70
  bytesBase64: zod.z.string().describe("Base64-encoded document bytes."),
71
- format: documents_js.DocumentFormatSchema.describe("The document format of bytesBase64 -- required, since inline bytes carry no filename to infer it from.")
71
+ format: documents_js.DocumentFormatSchema.describe("The document format of bytesBase64 — required, since inline bytes carry no filename to infer it from.")
72
72
  })]);
73
73
  /**
74
74
  * Resolves the hybrid DocumentInput union to concrete bytes and a format: for the path shape, reads the file from disk and infers its format from the extension (throwing if the extension is unrecognised); for the bytesBase64 shape, decodes the inline payload and uses the caller-supplied format directly.
@@ -95,7 +95,7 @@ async function resolveDocumentInput(input, options) {
95
95
  */
96
96
  const DocumentOutputSchema = zod.z.object({ outputPath: zod.z.string().optional().describe("Filesystem path to write the resulting document to. Omit to receive the document bytes inline, base64-encoded, in the tool result instead.") });
97
97
  /**
98
- * Above this many bytes, an inline base64 result is flagged `large: true` so a caller/LLM can see the response is sizeable before deciding whether to consume it directly. Purely advisory: `resolveDocumentOutput` never truncates or refuses to return large bytes, it only flags them -- silently truncating a document would produce a corrupt file with no indication anything was lost. 5 MB is a reasonable default order of magnitude for "an LLM context probably wants to know before this lands inline", well under typical MCP stdio transport limits.
98
+ * Above this many bytes, an inline base64 result is flagged `large: true` so a caller/LLM can see the response is sizeable before deciding whether to consume it directly. Purely advisory: `resolveDocumentOutput` never truncates or refuses to return large bytes, it only flags them — silently truncating a document would produce a corrupt file with no indication anything was lost. 5 MB is a reasonable default order of magnitude for "an LLM context probably wants to know before this lands inline", well under typical MCP stdio transport limits.
99
99
  */
100
100
  const LARGE_RESULT_THRESHOLD_BYTES = 5242880;
101
101
  /**
@@ -151,11 +151,11 @@ const FontInputSchema = zod.z.object({
151
151
  });
152
152
  const ConvertDocumentInputSchema = zod.z.object({
153
153
  source: DocumentInputSchema.describe("The document to convert."),
154
- targetFormat: documents_js.DocumentFormatSchema.describe("The format to convert the document to. Not every (source, targetFormat) pair is supported directly -- call list_document_conversions first to confirm this one is."),
154
+ targetFormat: documents_js.DocumentFormatSchema.describe("The format to convert the document to. Not every (source, targetFormat) pair is supported directly — call list_document_conversions first to confirm this one is."),
155
155
  output: DocumentOutputSchema.optional().describe("Where to write the converted document. Omit entirely to receive the bytes inline, base64-encoded, instead."),
156
156
  fonts: zod.z.array(FontInputSchema).optional().describe("Extra font faces to make available to the conversion, for a family the source document does not already embed. Only consulted by a conversion that runs a layout engine (a <format>-to-pdf conversion); every other conversion ignores this option entirely."),
157
- onSubstitutionDiagnostics: zod.z.boolean().optional().describe("When true, additionally report each individual font-substitution event as structured fontSubstitutions (which family/weight/style was requested, what it resolved to instead, and why). Every substitution is always reported as a plain diagnostic in `diagnostics` regardless of this flag -- this only controls whether the fuller, structured event is also collected."),
158
- images: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("A map from a markdown image destination (the part in the parentheses of ![](..)) to its base64-encoded PNG/JPEG bytes, for resolving a markdown source's own non-data: images. Only consulted by a markdown-sourced conversion; every other conversion ignores it. A destination absent from the map degrades to alt text, matching documents.js's own MarkdownImageResolver port -- a caller with no filesystem context has no other way to supply a relative path's bytes.")
157
+ onSubstitutionDiagnostics: zod.z.boolean().optional().describe("When true, additionally report each individual font-substitution event as structured fontSubstitutions (which family/weight/style was requested, what it resolved to instead, and why). Every substitution is always reported as a plain diagnostic in `diagnostics` regardless of this flag — this only controls whether the fuller, structured event is also collected."),
158
+ images: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("A map from a markdown image destination (the part in the parentheses of ![](..)) to its base64-encoded PNG/JPEG bytes, for resolving a markdown source's own non-data: images. Only consulted by a markdown-sourced conversion; every other conversion ignores it. A destination absent from the map degrades to alt text, matching documents.js's own MarkdownImageResolver port — a caller with no filesystem context has no other way to supply a relative path's bytes.")
159
159
  });
160
160
  const ConvertDocumentOutputSchema = zod.z.object({
161
161
  targetFormat: documents_js.DocumentFormatSchema,
@@ -172,7 +172,7 @@ const converter = (0, documents_js.createLocalDocumentConverter)();
172
172
  const convertDocumentOperation = defineOperation({
173
173
  name: "convert_document",
174
174
  title: "Convert document",
175
- description: "Converts a document from one supported format to another via documents.js's DocumentConverter port -- docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, rtf, wpd, doc, xls, ppt, epub, csv, svg, and pdf. Not every (source, targetFormat) pair is supported directly (odf, for instance, only ever converts to pdf); call list_document_conversions first to see which pairs actually are.",
175
+ description: "Converts a document from one supported format to another via documents.js's DocumentConverter port — docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, rtf, wpd, doc, xls, ppt, epub, csv, svg, and pdf. Not every (source, targetFormat) pair is supported directly (odf, for instance, only ever converts to pdf); call list_document_conversions first to see which pairs actually are.",
176
176
  inputSchema: ConvertDocumentInputSchema,
177
177
  outputSchema: ConvertDocumentOutputSchema,
178
178
  async run({ source, targetFormat, output, fonts, onSubstitutionDiagnostics, images }, context) {
@@ -213,7 +213,7 @@ const convertDocumentOperation = defineOperation({
213
213
  const listDocumentConversionsOperation = defineOperation({
214
214
  name: "list_document_conversions",
215
215
  title: "List document conversions",
216
- description: "Lists every (source, target) format pair convert_document actually supports, straight from documents.js's own DocumentConverter port -- the definitive source of truth for what convert_document will and will not accept as a (source, targetFormat) combination.",
216
+ description: "Lists every (source, target) format pair convert_document actually supports, straight from documents.js's own DocumentConverter port — the definitive source of truth for what convert_document will and will not accept as a (source, targetFormat) combination.",
217
217
  inputSchema: ListDocumentConversionsInputSchema,
218
218
  outputSchema: ListDocumentConversionsOutputSchema,
219
219
  run() {
@@ -268,7 +268,7 @@ const ComputeFormulaOutputSchema = zod.z.object({
268
268
  const computeFormulaOperation = defineOperation({
269
269
  name: "compute_formula",
270
270
  title: "Compute document formulas",
271
- description: "Reads every formula a document embeds (docx/odt/markdown paragraphs and pptx/odp slide shapes; a table cell's own blocks too -- docx's own reader recovers a real equation nested inside a table cell; structurally, the walk also covers a drawing page's own shape flow, though no writer in the family populates a formula there today; a spreadsheet's own cell-anchored formula objects; a standalone .odf formula document; and a formula nested inside another embedded object at any depth, e.g. a formula embedded in a drawing embedded in a spreadsheet) and evaluates each through document-compute.js's units-typed evaluate() -- a caller's way to check whether a document's stated arithmetic actually checks out. A formula referencing a symbol (e.g. F = m * a) needs that symbol's value supplied via bindings, keyed by the document's own symbol-table id (see the document's symbolTable.symbols[].id, or a returned formula's own latex to identify which symbol is which); a formula with no free symbols (units and numeric literals only) evaluates with no bindings at all. Each formula reports its own outcome independently -- 'evaluated' with the result, 'no-content' when the formula was never lowered to a computable MathExpression (the common case for a spreadsheet's own embedded formula object, or any format other than markdown, none of which yet stores the semantic layer on disk), or 'error' naming which document-compute.js error it hit (e.g. UnboundSymbolError) -- so one formula needing more bindings never blocks the others. Each entry's own `locate` field is the reliable way to tell two formulas in the same document apart -- a structural path guaranteed unique per formula -- unlike `sourcePath`, which several formats leave undefined or stamp with the identical constant across sibling formulas (markdown's own display-math lowering among them).",
271
+ description: "Reads every formula a document embeds (docx/odt/markdown paragraphs and pptx/odp slide shapes; a table cell's own blocks too — docx's own reader recovers a real equation nested inside a table cell; structurally, the walk also covers a drawing page's own shape flow, though no writer in the family populates a formula there today; a spreadsheet's own cell-anchored formula objects; a standalone .odf formula document; and a formula nested inside another embedded object at any depth, e.g. a formula embedded in a drawing embedded in a spreadsheet) and evaluates each through document-compute.js's units-typed evaluate() — a caller's way to check whether a document's stated arithmetic actually checks out. A formula referencing a symbol (e.g. F = m * a) needs that symbol's value supplied via bindings, keyed by the document's own symbol-table id (see the document's symbolTable.symbols[].id, or a returned formula's own latex to identify which symbol is which); a formula with no free symbols (units and numeric literals only) evaluates with no bindings at all. Each formula reports its own outcome independently — 'evaluated' with the result, 'no-content' when the formula was never lowered to a computable MathExpression (the common case for a spreadsheet's own embedded formula object, or any format other than markdown, none of which yet stores the semantic layer on disk), or 'error' naming which document-compute.js error it hit (e.g. UnboundSymbolError) — so one formula needing more bindings never blocks the others. Each entry's own `locate` field is the reliable way to tell two formulas in the same document apart — a structural path guaranteed unique per formula — unlike `sourcePath`, which several formats leave undefined or stamp with the identical constant across sibling formulas (markdown's own display-math lowering among them).",
272
272
  inputSchema: zod.z.object({
273
273
  source: DocumentInputSchema.describe("The document to read formulas from."),
274
274
  bindings: document_schema_js.FormulaBindingsSchema.optional().describe("Known values for symbols the document's formulas reference, keyed by symbol-table id (a Quantity { kind: 'quantity', magnitude, dimension } or an Interval { kind: 'interval', min, max, dimension } per symbol). Omit for a document whose formulas are fully closed (units and numeric literals only, no 'sym' nodes).")
@@ -299,7 +299,7 @@ const computeFormulaOperation = defineOperation({
299
299
  const docxExtrasOperation = defineOperationWithoutOutputSchema({
300
300
  name: "docx_extras",
301
301
  title: "Docx extras",
302
- description: "Reads a docx's own comments, footnotes, header/footer parts, and numbering definitions -- data documents.js's ContentDocument pivot cannot carry, so ordinary document-reading operations never see it. Returns the real DocxExtras object (comments/footnotes/headerFooterParts/sectionHeaderFooters/numbering) as structured data.",
302
+ description: "Reads a docx's own comments, footnotes, header/footer parts, and numbering definitions — data documents.js's ContentDocument pivot cannot carry, so ordinary document-reading operations never see it. Returns the real DocxExtras object (comments/footnotes/headerFooterParts/sectionHeaderFooters/numbering) as structured data.",
303
303
  inputSchema: zod.z.object({ source: DocumentInputSchema.describe("The docx document to read.") }),
304
304
  async run({ source }) {
305
305
  const { bytes } = await resolveDocumentInput(source);
@@ -329,7 +329,7 @@ const RunSchema = zod.z.object({
329
329
  sizePt: zod.z.number().positive().optional().describe("docx/odt only."),
330
330
  colorHex: zod.z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("6-digit hex colour (e.g. 'ff0000' or '#ff0000'). docx/odt only."),
331
331
  hyperlink: zod.z.string().optional().describe("markdown only."),
332
- code: zod.z.boolean().optional().describe("markdown only -- renders the run as an inline code span.")
332
+ code: zod.z.boolean().optional().describe("markdown only — renders the run as an inline code span.")
333
333
  });
334
334
  const ParagraphSchema = zod.z.object({
335
335
  text: zod.z.string().optional().describe("Plain paragraph text, as a single run. Omit and use `runs` instead for mixed formatting within one paragraph."),
@@ -348,7 +348,7 @@ function unsupportedFieldNames(input, unsupported) {
348
348
  }
349
349
  function rejectUnsupportedFields(input, unsupported, formatLabel, context) {
350
350
  const present = unsupportedFieldNames(input, unsupported);
351
- if (present.length > 0) throw new Error(`${context} does not support ${present.join(", ")} for ${formatLabel} -- remove ${present.length === 1 ? "it" : "them"} or target docx/odt instead.`);
351
+ if (present.length > 0) throw new Error(`${context} does not support ${present.join(", ")} for ${formatLabel} — remove ${present.length === 1 ? "it" : "them"} or target docx/odt instead.`);
352
352
  }
353
353
  const DOCX_ODT_UNSUPPORTED_RUN_FIELDS = ["hyperlink", "code"];
354
354
  const MARKDOWN_UNSUPPORTED_RUN_FIELDS = [
@@ -425,7 +425,7 @@ const ResolvedDocumentOutputSchema$2 = zod.z.union([zod.z.object({
425
425
  const documentCreateOperation = defineOperation({
426
426
  name: "document_create",
427
427
  title: "Create a blank document",
428
- description: "Creates a fresh, blank document in the given format via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...), the same construction document_append_paragraphs's own edit calls build on. Returns an empty document with no content -- follow with document_append_paragraphs (docx/odt/markdown) to add text.",
428
+ description: "Creates a fresh, blank document in the given format via documents.js's own live-view editors (createDocx/createOdt/createMarkdownEditor/...), the same construction document_append_paragraphs's own edit calls build on. Returns an empty document with no content — follow with document_append_paragraphs (docx/odt/markdown) to add text.",
429
429
  inputSchema: zod.z.object({
430
430
  format: WritableFormatSchema.describe("The format of document to create."),
431
431
  output: DocumentOutputSchema.optional().describe("Where to write the created document. Omit entirely to receive the bytes inline, base64-encoded.")
@@ -438,7 +438,7 @@ const documentCreateOperation = defineOperation({
438
438
  const documentAppendParagraphsOperation = defineOperation({
439
439
  name: "document_append_paragraphs",
440
440
  title: "Append paragraphs to a wordprocessing document",
441
- description: "Appends one or more paragraphs -- each optionally built from several independently-formatted runs -- to the end of a docx, odt, or markdown document, through documents.js's own live-view editors (the same DocxBody.appendParagraph/OdtBody.appendParagraph/MarkdownBody.appendParagraph document-cli's own TUI uses). Does not convert format -- the source document's own format and targetFormat must match. docx and odt share an identical field set (underline, fontFamily, sizePt, colorHex, headingLevel, alignment all supported); markdown supports a different, smaller set (hyperlink, code) and rejects the docx/odt-only fields outright rather than silently dropping them. This covers wordprocessing paragraph/run editing only -- slides, sheets, drawings, tables, lists, and images are a separate, larger editing surface not exposed here yet.",
441
+ description: "Appends one or more paragraphs — each optionally built from several independently-formatted runs — to the end of a docx, odt, or markdown document, through documents.js's own live-view editors (the same DocxBody.appendParagraph/OdtBody.appendParagraph/MarkdownBody.appendParagraph document-cli's own TUI uses). Does not convert format — the source document's own format and targetFormat must match. docx and odt share an identical field set (underline, fontFamily, sizePt, colorHex, headingLevel, alignment all supported); markdown supports a different, smaller set (hyperlink, code) and rejects the docx/odt-only fields outright rather than silently dropping them. This covers wordprocessing paragraph/run editing only — slides, sheets, drawings, tables, lists, and images are a separate, larger editing surface not exposed here yet.",
442
442
  inputSchema: zod.z.object({
443
443
  source: DocumentInputSchema.describe("The document to append paragraphs to."),
444
444
  targetFormat: zod.z.enum([
@@ -452,7 +452,7 @@ const documentAppendParagraphsOperation = defineOperation({
452
452
  outputSchema: ResolvedDocumentOutputSchema$2,
453
453
  async run({ source, targetFormat, paragraphs, output }) {
454
454
  const { bytes, format } = await resolveDocumentInput(source);
455
- if (format !== targetFormat) throw new Error(`source document is "${format}", but targetFormat is "${targetFormat}" -- document_append_paragraphs never converts format, so the two must match.`);
455
+ if (format !== targetFormat) throw new Error(`source document is "${format}", but targetFormat is "${targetFormat}" — document_append_paragraphs never converts format, so the two must match.`);
456
456
  let resultBytes;
457
457
  if (targetFormat === "markdown") {
458
458
  const editor = (0, documents_js.openMarkdown)((0, documents_js.decodeMarkdownText)(bytes));
@@ -508,7 +508,7 @@ const describeFontFileOperation = defineOperation({
508
508
  name: "describe_font_file",
509
509
  title: "Describe font file",
510
510
  description: "Reads a standalone TrueType/OpenType font file (.ttf/.otf) and reports the family/bold/italic triple it declares about itself.",
511
- inputSchema: zod.z.object({ source: FontFileInputSchema.describe("The standalone .ttf/.otf font file to inspect -- not a document.") }),
511
+ inputSchema: zod.z.object({ source: FontFileInputSchema.describe("The standalone .ttf/.otf font file to inspect — not a document.") }),
512
512
  outputSchema: zod.z.object({
513
513
  family: zod.z.string(),
514
514
  bold: zod.z.boolean(),
@@ -536,9 +536,9 @@ async function readSourceBytes(source) {
536
536
  const fromPackageOperation = defineOperation({
537
537
  name: "from_package",
538
538
  title: "Build document from package",
539
- description: "Rebuilds real document bytes in a target format from a DocumentTree previously serialised to JSON (e.g. by a caller's own --dump-package-equivalent step) -- the read side of the DocumentTree round trip a conversion's onDocument callback produces.",
539
+ description: "Rebuilds real document bytes in a target format from a DocumentTree previously serialised to JSON (e.g. by a caller's own --dump-package-equivalent step) — the read side of the DocumentTree round trip a conversion's onDocument callback produces.",
540
540
  inputSchema: zod.z.object({
541
- source: DocumentInputSchema.describe("The DocumentTree JSON to read. 'path' points at a JSON file on disk -- its extension is never used to infer a document format, since the file holds a DocumentTree, not a document. 'bytesBase64' carries the JSON inline; its 'format' field is required by the shared hybrid input shape but unused by this operation."),
541
+ source: DocumentInputSchema.describe("The DocumentTree JSON to read. 'path' points at a JSON file on disk — its extension is never used to infer a document format, since the file holds a DocumentTree, not a document. 'bytesBase64' carries the JSON inline; its 'format' field is required by the shared hybrid input shape but unused by this operation."),
542
542
  targetFormat: documents_js.DocumentFormatSchema.describe("The document format to build from the DocumentTree."),
543
543
  output: DocumentOutputSchema.optional().describe("Where to write the resulting document. Omit entirely (or omit outputPath within it) to receive the bytes inline instead.")
544
544
  }),
@@ -563,11 +563,11 @@ const fromPackageOperation = defineOperation({
563
563
  try {
564
564
  result = (0, documents_js.documentFromJson)(parsed);
565
565
  } catch (error) {
566
- if (error instanceof documents_js.UnrecognizedDocumentSchemaError) throw new Error("'source' has no recognised $schema -- only a file carrying a real DocumentTree (e.g. written by a caller's own --dump-package-equivalent step) can be read back by this operation", { cause: error });
566
+ if (error instanceof documents_js.UnrecognizedDocumentSchemaError) throw new Error("'source' has no recognised $schema — only a file carrying a real DocumentTree (e.g. written by a caller's own --dump-package-equivalent step) can be read back by this operation", { cause: error });
567
567
  if (error instanceof zod.z.ZodError) throw new Error(`'source' failed ${(0, documents_js.documentSchemaKindOf)(parsed)} validation: ${error.message}`, { cause: error });
568
568
  throw error;
569
569
  }
570
- if (result.kind !== "DocumentTree") throw new Error(`'source' is a ${result.kind}, not a DocumentTree -- only a file carrying a real DocumentTree (e.g. written by a caller's own --dump-package-equivalent step) can be read back by this operation`);
570
+ if (result.kind !== "DocumentTree") throw new Error(`'source' is a ${result.kind}, not a DocumentTree — only a file carrying a real DocumentTree (e.g. written by a caller's own --dump-package-equivalent step) can be read back by this operation`);
571
571
  return resolveDocumentOutput((0, documents_js.buildDocumentBytes)(result.value, targetFormat), output ?? {});
572
572
  }
573
573
  });
@@ -592,10 +592,10 @@ const ResolvedDocumentOutputSchema = zod.z.union([zod.z.object({
592
592
  const metadataWriteOperation = defineOperation({
593
593
  name: "metadata_write",
594
594
  title: "Write document metadata",
595
- description: "Patches a document's own title/author/subject/keywords, leaving every other field and every other flag as-is. Does not convert format -- the source document's own format and targetFormat must match (or both be 'pdf'); odf (a standalone formula document) is rejected outright as either a source or a target, since it has no write path back out at all. Convert the document to a different format first (e.g. with a documents.js conversion operation) if metadata needs to be set on the result of a format change.",
595
+ description: "Patches a document's own title/author/subject/keywords, leaving every other field and every other flag as-is. Does not convert format — the source document's own format and targetFormat must match (or both be 'pdf'); odf (a standalone formula document) is rejected outright as either a source or a target, since it has no write path back out at all. Convert the document to a different format first (e.g. with a documents.js conversion operation) if metadata needs to be set on the result of a format change.",
596
596
  inputSchema: zod.z.object({
597
597
  source: DocumentInputSchema.describe("The document to patch metadata on."),
598
- targetFormat: documents_js.DocumentFormatSchema.describe("The format to write the patched document back out as -- must match the source document's own format (or both be 'pdf'). metadata_write never converts format."),
598
+ targetFormat: documents_js.DocumentFormatSchema.describe("The format to write the patched document back out as — must match the source document's own format (or both be 'pdf'). metadata_write never converts format."),
599
599
  output: DocumentOutputSchema.optional().describe("Where to write the patched document. Omit entirely to receive the bytes inline, base64-encoded."),
600
600
  setTitle: zod.z.string().optional().describe("Set the title field. Omit to leave it exactly as the source document already has it."),
601
601
  setAuthor: zod.z.string().optional().describe("Set the author field. Omit to leave it exactly as the source document already has it."),
@@ -615,7 +615,7 @@ const metadataWriteOperation = defineOperation({
615
615
  });
616
616
  //#endregion
617
617
  //#region src/operations/odb.ts
618
- const ODB_SOURCE_DESCRIPTION = ".odb database to read. 'path' points at the .odb file on disk -- its extension is never used to infer a document format, since documents.js deliberately excludes 'odb' from DocumentFormat (an embedded database front end has no single natural target format -- tables, saved queries, and reports are three unrelated output shapes -- see that package's own README). 'bytesBase64' carries the .odb bytes inline; its 'format' field is required by the shared hybrid input shape but unused by every odb operation.";
618
+ const ODB_SOURCE_DESCRIPTION = ".odb database to read. 'path' points at the .odb file on disk — its extension is never used to infer a document format, since documents.js deliberately excludes 'odb' from DocumentFormat (an embedded database front end has no single natural target format — tables, saved queries, and reports are three unrelated output shapes — see that package's own README). 'bytesBase64' carries the .odb bytes inline; its 'format' field is required by the shared hybrid input shape but unused by every odb operation.";
619
619
  async function resolveOdbBytes(source) {
620
620
  if ("path" in source) {
621
621
  const buffer = await (0, node_fs_promises.readFile)(source.path);
@@ -623,11 +623,11 @@ async function resolveOdbBytes(source) {
623
623
  }
624
624
  return (0, documents_js.base64ToBytes)(source.bytesBase64);
625
625
  }
626
- /** Resolves an .odb DocumentInput straight through to a decoded Package (via documents.js's own decodeOdbPackage) -- the shape every read (as opposed to export) odb operation needs. */
626
+ /** Resolves an .odb DocumentInput straight through to a decoded Package (via documents.js's own decodeOdbPackage) — the shape every read (as opposed to export) odb operation needs. */
627
627
  async function resolveOdbPackage(source) {
628
628
  return (0, documents_js.decodeOdbPackage)(await resolveOdbBytes(source));
629
629
  }
630
- /** Resolves a saved query's own SQL text by name against the .odb's own db:queries (read via readOdbInventory) -- odb_query's own equivalent of document-cli's resolveQuerySql, for the case where the caller named a saved query rather than supplying SQL directly. Throws, naming every available query, when the name doesn't resolve. */
630
+ /** Resolves a saved query's own SQL text by name against the .odb's own db:queries (read via readOdbInventory) — odb_query's own equivalent of document-cli's resolveQuerySql, for the case where the caller named a saved query rather than supplying SQL directly. Throws, naming every available query, when the name doesn't resolve. */
631
631
  function resolveSavedQuerySql(pkg, name) {
632
632
  const inventory = (0, documents_js.readOdbInventory)(pkg);
633
633
  const saved = inventory.queries.find((candidate) => candidate.name === name);
@@ -654,7 +654,7 @@ const OdbSourceInputSchema = zod.z.object({ source: DocumentInputSchema.describe
654
654
  const odbTablesOperation = defineOperationWithoutOutputSchema({
655
655
  name: "odb_tables",
656
656
  title: "List .odb tables",
657
- description: "Lists every table an embedded .odb database declares -- column names, types, and row data -- across every storage tier documents.js supports (HSQLDB TEXT/CACHED/BINARY script formats, Firebird gbak backups).",
657
+ description: "Lists every table an embedded .odb database declares — column names, types, and row data — across every storage tier documents.js supports (HSQLDB TEXT/CACHED/BINARY script formats, Firebird gbak backups).",
658
658
  inputSchema: OdbSourceInputSchema,
659
659
  async run({ source }) {
660
660
  return (0, documents_js.readOdbTables)(await resolveOdbPackage(source));
@@ -681,7 +681,7 @@ const odbReportsOperation = defineOperationWithoutOutputSchema({
681
681
  const odbQueryOperation = defineOperationWithoutOutputSchema({
682
682
  name: "odb_query",
683
683
  title: "Query an .odb database",
684
- description: "Runs a bounded SELECT (with optional JOINs of any kind, table aliases, a derived table in FROM, and IN/EXISTS subqueries) over an embedded .odb database's own extracted tables, given directly as SQL or by naming one of the database's saved queries. No database engine is involved -- the query runs in memory over the same tables odb_tables would return, against a closed grammar (SELECT/FROM/JOIN [INNER|LEFT [OUTER]|RIGHT [OUTER]|FULL [OUTER]|CROSS|NATURAL] ... [ON|USING]/WHERE/GROUP BY/ORDER BY, with an optional [AS] alias on any table, WHERE and ON also accepting [NOT] IN (SELECT ...) and [NOT] EXISTS (SELECT ...) -- no column aliases); an unsupported construct is reported as an error naming it, never silently ignored.",
684
+ description: "Runs a bounded SELECT (with optional JOINs of any kind, table aliases, a derived table in FROM, and IN/EXISTS subqueries) over an embedded .odb database's own extracted tables, given directly as SQL or by naming one of the database's saved queries. No database engine is involved — the query runs in memory over the same tables odb_tables would return, against a closed grammar (SELECT/FROM/JOIN [INNER|LEFT [OUTER]|RIGHT [OUTER]|FULL [OUTER]|CROSS|NATURAL] ... [ON|USING]/WHERE/GROUP BY/ORDER BY, with an optional [AS] alias on any table, WHERE and ON also accepting [NOT] IN (SELECT ...) and [NOT] EXISTS (SELECT ...) — no column aliases); an unsupported construct is reported as an error naming it, never silently ignored.",
685
685
  inputSchema: zod.z.object({
686
686
  source: DocumentInputSchema.describe(ODB_SOURCE_DESCRIPTION),
687
687
  sql: zod.z.string().describe("A literal SELECT statement to run. Mutually exclusive with \"query\".").optional(),
@@ -700,7 +700,7 @@ const odbToCsvOperation = defineOperationWithoutOutputSchema({
700
700
  description: "Extracts exactly one named table from an embedded .odb database as CSV bytes. The table name is required whenever the database declares more than one table.",
701
701
  inputSchema: zod.z.object({
702
702
  source: DocumentInputSchema.describe(ODB_SOURCE_DESCRIPTION),
703
- table: zod.z.string().describe("The table to export -- required when the .odb declares more than one table.").optional(),
703
+ table: zod.z.string().describe("The table to export — required when the .odb declares more than one table.").optional(),
704
704
  output: DocumentOutputSchema.optional().describe("Where to write the resulting CSV. Omit entirely (or omit outputPath within it) to receive the bytes inline instead.")
705
705
  }),
706
706
  async run({ source, table, output }, context) {
@@ -732,11 +732,11 @@ const OdbRenderReportTargetFormatSchema = zod.z.enum([
732
732
  "pdf"
733
733
  ]);
734
734
  const OdbRenderReportInputSchema = zod.z.object({
735
- source: DocumentInputSchema.describe(".odb database to render a report from. 'path' points at the .odb file on disk -- its extension is never used to infer a document format, since documents.js deliberately excludes 'odb' from DocumentFormat (an embedded database front end has no single natural target format -- tables, saved queries, and reports are three unrelated output shapes -- see that package's own README). 'bytesBase64' carries the .odb bytes inline; its 'format' field is required by the shared hybrid input shape but unused by this operation."),
736
- report: zod.z.string().optional().describe("The name of the report to render. Required only when the .odb declares more than one report -- omitting it when exactly one is declared renders that one automatically."),
735
+ source: DocumentInputSchema.describe(".odb database to render a report from. 'path' points at the .odb file on disk — its extension is never used to infer a document format, since documents.js deliberately excludes 'odb' from DocumentFormat (an embedded database front end has no single natural target format — tables, saved queries, and reports are three unrelated output shapes — see that package's own README). 'bytesBase64' carries the .odb bytes inline; its 'format' field is required by the shared hybrid input shape but unused by this operation."),
736
+ report: zod.z.string().optional().describe("The name of the report to render. Required only when the .odb declares more than one report — omitting it when exactly one is declared renders that one automatically."),
737
737
  targetFormat: OdbRenderReportTargetFormatSchema.describe("The format to render the report into."),
738
738
  output: DocumentOutputSchema.optional().describe("Where to write the rendered report. Omit entirely (or omit outputPath within it) to receive the bytes inline instead."),
739
- fonts: zod.z.array(FontInputSchema).optional().describe("Extra font faces to make available, for a family the rendered report's own text otherwise falls back on. Only consulted when targetFormat is 'pdf' -- docx and odt output is genuine editable text with no font-embedding step of its own, so fonts is ignored for those two targets.")
739
+ fonts: zod.z.array(FontInputSchema).optional().describe("Extra font faces to make available, for a family the rendered report's own text otherwise falls back on. Only consulted when targetFormat is 'pdf' — docx and odt output is genuine editable text with no font-embedding step of its own, so fonts is ignored for those two targets.")
740
740
  });
741
741
  const MathDiagnosticSchema = zod.z.object({
742
742
  kind: zod.z.enum(["unsupported-element", "approximated-element"]),
@@ -773,7 +773,7 @@ const OdbRenderReportOutputSchema = zod.z.union([zod.z.object({
773
773
  const odbRenderReportOperation = defineOperation({
774
774
  name: "odb_render_report",
775
775
  title: "Render .odb report",
776
- description: "Resolves one of an .odb database's own reports -- its data-bound command run through the bounded SQL engine, its rpt: formulas evaluated, its bands laid out -- and renders the result to docx, odt, or pdf.",
776
+ description: "Resolves one of an .odb database's own reports — its data-bound command run through the bounded SQL engine, its rpt: formulas evaluated, its bands laid out — and renders the result to docx, odt, or pdf.",
777
777
  inputSchema: OdbRenderReportInputSchema,
778
778
  outputSchema: OdbRenderReportOutputSchema,
779
779
  async run({ source, report, targetFormat, output, fonts }, context) {
@@ -820,7 +820,7 @@ async function resolveOdmMasterBytes(source) {
820
820
  }
821
821
  const OdmChapterInputSchema = zod.z.object({
822
822
  href: zod.z.string().describe("The chapter's own text:section-source href as declared inside the .odm master document (e.g. '../chapter1.odt')."),
823
- source: DocumentInputSchema.describe("The chapter document's own bytes -- always read as odt, regardless of the format this hybrid input declares.")
823
+ source: DocumentInputSchema.describe("The chapter document's own bytes — always read as odt, regardless of the format this hybrid input declares.")
824
824
  });
825
825
  const OdmToPdfInputSchema = zod.z.object({
826
826
  source: OdmMasterSourceSchema.describe("The .odm master document to convert."),
@@ -839,7 +839,7 @@ const OdmToPdfOutputSchema = zod.z.union([zod.z.object({
839
839
  const odmToPdfOperation = defineOperation({
840
840
  name: "odm_to_pdf",
841
841
  title: "Convert ODM master document to PDF",
842
- description: "Converts a .odm (ODF master document) to PDF. A .odm never carries its own chapters' content inline -- every text:section is a bare external reference to a standalone .odt file -- so each chapter the master document declares must resolve through `chapters` (an explicit href -> document override) and/or `chaptersDir` (a directory searched by the href's own basename), checked in that order. A chapter left unresolved by both fails the whole conversion, naming every unresolved href.",
842
+ description: "Converts a .odm (ODF master document) to PDF. A .odm never carries its own chapters' content inline — every text:section is a bare external reference to a standalone .odt file — so each chapter the master document declares must resolve through `chapters` (an explicit href -> document override) and/or `chaptersDir` (a directory searched by the href's own basename), checked in that order. A chapter left unresolved by both fails the whole conversion, naming every unresolved href.",
843
843
  inputSchema: OdmToPdfInputSchema,
844
844
  outputSchema: OdmToPdfOutputSchema,
845
845
  async run({ source, chapters, chaptersDir, output }) {
@@ -880,7 +880,7 @@ function toOutlineJson(children) {
880
880
  const outlineDocumentOperation = defineOperationWithoutOutputSchema({
881
881
  name: "outline_document",
882
882
  title: "Outline document",
883
- description: "Projects a document's table of contents as a structured outline: reads the source's own native DocumentTree directly (documents.js's readNativeDocumentTree -- no bridging conversion, no discarded output bytes) and runs document-outline.js's buildOutline over it. Groups carry { text, level, children } (a heading's, list item's, slide's, sheet's, or page's own label plus nested children); leaves carry { kind, text }.",
883
+ description: "Projects a document's table of contents as a structured outline: reads the source's own native DocumentTree directly (documents.js's readNativeDocumentTree — no bridging conversion, no discarded output bytes) and runs document-outline.js's buildOutline over it. Groups carry { text, level, children } (a heading's, list item's, slide's, sheet's, or page's own label plus nested children); leaves carry { kind, text }.",
884
884
  inputSchema: zod.z.object({ source: DocumentInputSchema.describe("The document to outline.") }),
885
885
  async run({ source }, context) {
886
886
  const signal = context?.signal;
@@ -934,7 +934,7 @@ const pdfInspectOperation = defineOperationWithoutOutputSchema({
934
934
  //#endregion
935
935
  //#region src/registry.ts
936
936
  /**
937
- * Every document operation this package defines, one entry per MCP tool/CLI command/REST route -- "the same registry as the MCP" a consumer that needs to enumerate every operation (rather than importing one by name) reaches for: an MCP server registers each entry as a tool, a REST server adds one route per entry, and a CLI can validate its own parsed flags against an entry's inputSchema before dispatching to its run().
937
+ * Every document operation this package defines, one entry per MCP tool/CLI command/REST route — "the same registry as the MCP" a consumer that needs to enumerate every operation (rather than importing one by name) reaches for: an MCP server registers each entry as a tool, a REST server adds one route per entry, and a CLI can validate its own parsed flags against an entry's inputSchema before dispatching to its run().
938
938
  */
939
939
  const DOCUMENT_OPERATIONS = [
940
940
  convertDocumentOperation,