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 +37 -37
- package/dist/index.d.cts +41 -41
- package/dist/index.d.ts +41 -41
- package/dist/index.js +37 -37
- package/package.json +7 -7
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>>`
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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}"
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
736
|
-
report: zod.z.string().optional().describe("The name of the report to render. Required only when the .odb declares more than one report
|
|
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'
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|