@tiwater/office-mcp 0.21.22 → 0.21.28
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/office/contracts/docx_fill_table_from_tables.schema.json +2 -1
- package/office/contracts/docx_replace_content_from_source.schema.json +3 -3
- package/office/contracts/docx_set_paragraph_pagination.schema.json +36 -0
- package/office/contracts/docx_set_table_body.schema.json +8 -1
- package/office/contracts/docx_table_index.schema.json +0 -6
- package/office/contracts/tiwater-office-provider-contract-manifest-v1.json +31 -9
- package/office/contracts/xlsx_read_range.schema.json +47 -0
- package/office/docx-object-identity.mjs +11 -0
- package/office/index.mjs +115 -46
- package/package.json +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "tiwater.office-mcp-input/docx_fill_table_from_tables",
|
|
4
|
+
"description": "Project source-table rows into one target template table atomically. Use this instead of manually rebuilding rows when target cells derive from source tables. Target formatting is reused, and native vertical-merge owners are preserved within each source range.",
|
|
4
5
|
"type": "object",
|
|
5
6
|
"properties": {
|
|
6
7
|
"input": { "type": "string", "minLength": 1, "description": "Current target DOCX.", "x-tiwater-file-role": "read" },
|
|
@@ -96,7 +97,7 @@
|
|
|
96
97
|
},
|
|
97
98
|
"recordColumn": {
|
|
98
99
|
"type": "object",
|
|
99
|
-
"description": "Source grid-column address
|
|
100
|
+
"description": "Source grid-column address that defines output-row records. Choose an unmerged column when every physical source row must remain an output row; vertical merges in other mapped columns are still preserved. Choose a merged column only when every mapping into one target cell has one equal scalar value throughout that merge group.",
|
|
100
101
|
"properties": {
|
|
101
102
|
"part": { "type": "string", "minLength": 1, "pattern": "^\\/" },
|
|
102
103
|
"path": { "type": "string", "pattern": "^\\/[A-Za-z_][A-Za-z0-9_.-]*:[A-Za-z_][A-Za-z0-9_.-]*\\[[1-9][0-9]*\\](?:\\/[A-Za-z_][A-Za-z0-9_.-]*:[A-Za-z_][A-Za-z0-9_.-]*\\[[1-9][0-9]*\\])*$" }
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
"sourceSelections": {
|
|
45
45
|
"minItems": 1,
|
|
46
46
|
"type": "array",
|
|
47
|
-
"description": "Ordered native source paragraphs, runs, or text nodes.
|
|
47
|
+
"description": "Ordered native source cells, paragraphs, runs, or text nodes. Consecutive run or text selections from one source paragraph form one target paragraph; a range retains the native runs it crosses. A source paragraph boundary remains a target paragraph boundary. Selected content becomes the target content without Agent transcription.",
|
|
48
48
|
"items": {
|
|
49
49
|
"type": "object",
|
|
50
50
|
"properties": {
|
|
51
51
|
"address": {
|
|
52
52
|
"type": "object",
|
|
53
|
-
"description": "Native source object address returned by docx_read_object or docx_read_table. Selecting a paragraph copies that paragraph's inline content; selecting a cell copies its direct paragraphs.",
|
|
53
|
+
"description": "Native source object address returned by docx_read_object or docx_read_table. Selecting a paragraph copies that paragraph's inline content; selecting a cell copies its direct paragraphs; selecting a run or text copies native inline content and formatting.",
|
|
54
54
|
"properties": {
|
|
55
55
|
"part": {
|
|
56
56
|
"type": "string",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"range": {
|
|
72
72
|
"type": "object",
|
|
73
|
-
"description": "Optional Unicode-scalar substring of
|
|
73
|
+
"description": "Optional Unicode-scalar substring of the selected object's observed text. For a cell, offsets use its docx_read_table text with one newline between direct paragraphs. The selected native runs and paragraph boundaries are retained. Omit it to copy the complete selected object.",
|
|
74
74
|
"properties": {
|
|
75
75
|
"start": {
|
|
76
76
|
"type": "integer",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "tiwater.office-mcp-input/docx_set_paragraph_pagination",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": { "type": "string", "minLength": 1, "x-tiwater-file-role": "read" },
|
|
7
|
+
"changes": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"minItems": 1,
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"paragraph": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"properties": {
|
|
16
|
+
"part": { "type": "string", "minLength": 1, "pattern": "^\\/" },
|
|
17
|
+
"path": { "type": "string", "pattern": "^\\/[A-Za-z_][A-Za-z0-9_.-]*:[A-Za-z_][A-Za-z0-9_.-]*\\[[1-9][0-9]*\\](?:\\/[A-Za-z_][A-Za-z0-9_.-]*:[A-Za-z_][A-Za-z0-9_.-]*\\[[1-9][0-9]*\\])*$" }
|
|
18
|
+
},
|
|
19
|
+
"required": ["part", "path"],
|
|
20
|
+
"additionalProperties": false
|
|
21
|
+
},
|
|
22
|
+
"keepWithNext": { "type": "boolean", "description": "Keep this paragraph on the same page as the immediately following paragraph or table. This does not guarantee that a table header remains with its first body row." },
|
|
23
|
+
"keepLinesTogether": { "type": "boolean", "description": "Keep all lines of this paragraph on one page." },
|
|
24
|
+
"pageBreakBefore": { "type": "boolean", "description": "Start this paragraph on a new page." },
|
|
25
|
+
"preventWidowOrphanLines": { "type": "boolean", "description": "Prevent a single first or last line from being isolated across pages." }
|
|
26
|
+
},
|
|
27
|
+
"required": ["paragraph"],
|
|
28
|
+
"additionalProperties": false
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"output": { "type": "string", "minLength": 1, "description": "Output DOCX path; may equal input for one atomic in-place update.", "x-tiwater-file-role": "write" },
|
|
32
|
+
"receiptOutput": { "type": "string", "minLength": 1, "x-tiwater-file-role": "write", "x-tiwater-file-effect": false }
|
|
33
|
+
},
|
|
34
|
+
"required": ["input", "changes", "output", "receiptOutput"],
|
|
35
|
+
"additionalProperties": false
|
|
36
|
+
}
|
|
@@ -94,7 +94,10 @@
|
|
|
94
94
|
"description": "One or more contiguous request-local column IDs occupied by this cell.",
|
|
95
95
|
"items": { "type": "string", "minLength": 1, "maxLength": 80 }
|
|
96
96
|
},
|
|
97
|
-
"text": {
|
|
97
|
+
"text": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Final plain text for this cell. If the current cell at the same row and grid span already has exactly this text, its native paragraphs and run formatting are retained while row and merge properties are updated."
|
|
100
|
+
},
|
|
98
101
|
"rowSpan": {
|
|
99
102
|
"type": "integer",
|
|
100
103
|
"minimum": 1,
|
|
@@ -105,6 +108,10 @@
|
|
|
105
108
|
"required": ["columns", "text"],
|
|
106
109
|
"additionalProperties": false
|
|
107
110
|
}
|
|
111
|
+
},
|
|
112
|
+
"cantSplit": {
|
|
113
|
+
"type": "boolean",
|
|
114
|
+
"description": "Whether Word may split this physical row across pages. Omit to preserve the prototype row property."
|
|
108
115
|
}
|
|
109
116
|
},
|
|
110
117
|
"required": ["prototypeRow", "cells"],
|
|
@@ -19,12 +19,6 @@
|
|
|
19
19
|
"description": "Optional new JSON artifact path for retaining the complete table index. May be combined with returnContent.",
|
|
20
20
|
"x-tiwater-file-role": "write"
|
|
21
21
|
},
|
|
22
|
-
"limit": {
|
|
23
|
-
"type": "integer",
|
|
24
|
-
"minimum": 1,
|
|
25
|
-
"maximum": 1000,
|
|
26
|
-
"description": "Maximum number of table summaries requested in this response page. The provider may return fewer to keep the machine response bounded."
|
|
27
|
-
},
|
|
28
22
|
"offset": {
|
|
29
23
|
"type": "integer",
|
|
30
24
|
"minimum": 0,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema": "tiwater.office-provider-contract-manifest/v1",
|
|
3
3
|
"provider": {
|
|
4
4
|
"id": "@tiwater/office-mcp",
|
|
5
|
-
"version": "0.21.
|
|
5
|
+
"version": "0.21.28"
|
|
6
6
|
},
|
|
7
7
|
"tools": [
|
|
8
8
|
{
|
|
@@ -75,11 +75,11 @@
|
|
|
75
75
|
"name": "docx_fill_table_from_tables",
|
|
76
76
|
"providerContract": {
|
|
77
77
|
"source": "packages/docx-cli/contracts/mcp-input/docx_fill_table_from_tables.schema.json",
|
|
78
|
-
"sha256": "
|
|
78
|
+
"sha256": "4e80fff1c08fd16f8a5b4c638cf6469aa51e3a499743b44f3bf900ae7194ea9b"
|
|
79
79
|
},
|
|
80
80
|
"inputContract": {
|
|
81
81
|
"path": "office/contracts/docx_fill_table_from_tables.schema.json",
|
|
82
|
-
"sha256": "
|
|
82
|
+
"sha256": "4e80fff1c08fd16f8a5b4c638cf6469aa51e3a499743b44f3bf900ae7194ea9b"
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
85
|
{
|
|
@@ -174,11 +174,11 @@
|
|
|
174
174
|
"name": "docx_replace_content_from_source",
|
|
175
175
|
"providerContract": {
|
|
176
176
|
"source": "packages/docx-cli/contracts/mcp-input/docx_replace_content_from_source.schema.json",
|
|
177
|
-
"sha256": "
|
|
177
|
+
"sha256": "3ce7730317f1b9429f5da38b0eaecb53664a056545904a7f3904cdf148b94ad1"
|
|
178
178
|
},
|
|
179
179
|
"inputContract": {
|
|
180
180
|
"path": "office/contracts/docx_replace_content_from_source.schema.json",
|
|
181
|
-
"sha256": "
|
|
181
|
+
"sha256": "3ce7730317f1b9429f5da38b0eaecb53664a056545904a7f3904cdf148b94ad1"
|
|
182
182
|
}
|
|
183
183
|
},
|
|
184
184
|
{
|
|
@@ -192,15 +192,26 @@
|
|
|
192
192
|
"sha256": "25f4d4e7c69fa5a2c4a82621aa58ea8eda21245636f84f2243ca4e9092616b68"
|
|
193
193
|
}
|
|
194
194
|
},
|
|
195
|
+
{
|
|
196
|
+
"name": "docx_set_paragraph_pagination",
|
|
197
|
+
"providerContract": {
|
|
198
|
+
"source": "packages/docx-cli/contracts/mcp-input/docx_set_paragraph_pagination.schema.json",
|
|
199
|
+
"sha256": "ccb90bb5b811cfc82985050094637b1afe4c9daf51d7243c0d81b2d63d875825"
|
|
200
|
+
},
|
|
201
|
+
"inputContract": {
|
|
202
|
+
"path": "office/contracts/docx_set_paragraph_pagination.schema.json",
|
|
203
|
+
"sha256": "ccb90bb5b811cfc82985050094637b1afe4c9daf51d7243c0d81b2d63d875825"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
195
206
|
{
|
|
196
207
|
"name": "docx_set_table_body",
|
|
197
208
|
"providerContract": {
|
|
198
209
|
"source": "packages/docx-cli/contracts/mcp-input/docx_set_table_body.schema.json",
|
|
199
|
-
"sha256": "
|
|
210
|
+
"sha256": "adb0898a253a60fc80e3e811fdd6d19ac01ae76abe16b077e8af1f0960b640af"
|
|
200
211
|
},
|
|
201
212
|
"inputContract": {
|
|
202
213
|
"path": "office/contracts/docx_set_table_body.schema.json",
|
|
203
|
-
"sha256": "
|
|
214
|
+
"sha256": "adb0898a253a60fc80e3e811fdd6d19ac01ae76abe16b077e8af1f0960b640af"
|
|
204
215
|
}
|
|
205
216
|
},
|
|
206
217
|
{
|
|
@@ -240,11 +251,11 @@
|
|
|
240
251
|
"name": "docx_table_index",
|
|
241
252
|
"providerContract": {
|
|
242
253
|
"source": "packages/docx-cli/contracts/mcp-input/docx_table_index.schema.json",
|
|
243
|
-
"sha256": "
|
|
254
|
+
"sha256": "737052f653fe0d222bfc2b808e0fbc298376ab88cf052352888ff02e5b71ed52"
|
|
244
255
|
},
|
|
245
256
|
"inputContract": {
|
|
246
257
|
"path": "office/contracts/docx_table_index.schema.json",
|
|
247
|
-
"sha256": "
|
|
258
|
+
"sha256": "737052f653fe0d222bfc2b808e0fbc298376ab88cf052352888ff02e5b71ed52"
|
|
248
259
|
}
|
|
249
260
|
},
|
|
250
261
|
{
|
|
@@ -445,6 +456,17 @@
|
|
|
445
456
|
"sha256": "9ae4a846a8ca5b9059dcfd2a589e9872a2ab8d4ba3a118a513f3e05462f923d0"
|
|
446
457
|
}
|
|
447
458
|
},
|
|
459
|
+
{
|
|
460
|
+
"name": "xlsx_read_range",
|
|
461
|
+
"providerContract": {
|
|
462
|
+
"source": "packages/xlsx-cli/contracts/mcp-input/xlsx_read_range.schema.json",
|
|
463
|
+
"sha256": "04b0ce1b912047f774fbbbb6ba7cf55e5e53a9b74d6f027d9c21b4d6d7397225"
|
|
464
|
+
},
|
|
465
|
+
"inputContract": {
|
|
466
|
+
"path": "office/contracts/xlsx_read_range.schema.json",
|
|
467
|
+
"sha256": "04b0ce1b912047f774fbbbb6ba7cf55e5e53a9b74d6f027d9c21b4d6d7397225"
|
|
468
|
+
}
|
|
469
|
+
},
|
|
448
470
|
{
|
|
449
471
|
"name": "xlsx_set_cell_number_format",
|
|
450
472
|
"providerContract": {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "tiwater.office-mcp-input/xlsx_read_range/v1",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"minLength": 1,
|
|
9
|
+
"description": "Current XLSX workbook. Convert legacy XLS before selecting Open XML cells.",
|
|
10
|
+
"x-tiwater-file-role": "read"
|
|
11
|
+
},
|
|
12
|
+
"sheet": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"minLength": 1,
|
|
15
|
+
"description": "Exact current worksheet name returned by workbook observation."
|
|
16
|
+
},
|
|
17
|
+
"range": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"pattern": "^[A-Za-z]{1,3}[1-9][0-9]*(?::[A-Za-z]{1,3}[1-9][0-9]*)?$",
|
|
20
|
+
"description": "Explicit native A1 cell or rectangular range. A single cell is a one-cell range."
|
|
21
|
+
},
|
|
22
|
+
"offset": {
|
|
23
|
+
"type": "integer",
|
|
24
|
+
"minimum": 0,
|
|
25
|
+
"maximum": 9007199254740991,
|
|
26
|
+
"description": "Zero-based cell offset in row-major order within the selected range. Continue only when another selected cell is needed."
|
|
27
|
+
},
|
|
28
|
+
"limit": {
|
|
29
|
+
"type": "integer",
|
|
30
|
+
"minimum": 1,
|
|
31
|
+
"maximum": 256,
|
|
32
|
+
"description": "Maximum selected cells in this bounded page."
|
|
33
|
+
},
|
|
34
|
+
"returnContent": {
|
|
35
|
+
"type": "boolean",
|
|
36
|
+
"description": "Return this selected technical page directly when it fits the response limit. May be combined with output."
|
|
37
|
+
},
|
|
38
|
+
"output": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1,
|
|
41
|
+
"description": "Optional immutable JSON artifact path for this selected technical page. May be combined with returnContent.",
|
|
42
|
+
"x-tiwater-file-role": "write"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"required": ["input", "sheet", "range", "limit", "returnContent"],
|
|
46
|
+
"additionalProperties": false
|
|
47
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function compactDocxObjectIdentity(object) {
|
|
2
|
+
return {
|
|
3
|
+
address: object.address,
|
|
4
|
+
parentAddress: object.parentAddress ?? null,
|
|
5
|
+
kind: object.kind,
|
|
6
|
+
textPreview: object.textPreview ?? null,
|
|
7
|
+
gridSpan: object.gridSpan ?? null,
|
|
8
|
+
verticalMerge: object.verticalMerge ?? null,
|
|
9
|
+
verticalTextAlignment: object.verticalTextAlignment ?? null,
|
|
10
|
+
};
|
|
11
|
+
}
|
package/office/index.mjs
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
writeJsonArtifact,
|
|
24
24
|
} from '../_shared/large-json-result.mjs';
|
|
25
25
|
import { withOutputWriteLock } from '../_shared/output-write-lock.mjs';
|
|
26
|
+
import { compactDocxObjectIdentity } from './docx-object-identity.mjs';
|
|
26
27
|
|
|
27
28
|
const packageMetadata = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
|
|
28
29
|
const inputContractManifest = JSON.parse(await readFile(
|
|
@@ -201,6 +202,67 @@ const xlsxInspectionSummary = z.object({
|
|
|
201
202
|
}).strict()).max(6),
|
|
202
203
|
}).strict();
|
|
203
204
|
|
|
205
|
+
const xlsxRangePageSummary = z.object({
|
|
206
|
+
schema: z.literal('tiwater.xlsx-range-page-receipt/v1'),
|
|
207
|
+
totalCellCount: z.number().int().nonnegative(),
|
|
208
|
+
returnedCellCount: z.number().int().nonnegative(),
|
|
209
|
+
remaining: z.number().int().nonnegative(),
|
|
210
|
+
nextOffset: z.number().int().nonnegative().nullable(),
|
|
211
|
+
}).strict();
|
|
212
|
+
|
|
213
|
+
const xlsxRangePage = z.object({
|
|
214
|
+
schema: z.literal('tiwater.xlsx-range-page/v1'),
|
|
215
|
+
toolVersion: z.string(),
|
|
216
|
+
file: z.string(),
|
|
217
|
+
inputSha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
218
|
+
sheet: z.string(),
|
|
219
|
+
range: z.string(),
|
|
220
|
+
receipt: xlsxRangePageSummary,
|
|
221
|
+
cells: z.array(z.object({
|
|
222
|
+
reference: z.string(),
|
|
223
|
+
row: z.number().int().positive(),
|
|
224
|
+
column: z.number().int().positive(),
|
|
225
|
+
physical: z.boolean(),
|
|
226
|
+
rawValue: z.string().nullable(),
|
|
227
|
+
formattedValue: z.string().nullable(),
|
|
228
|
+
valueType: z.string().nullable(),
|
|
229
|
+
normalizedValue: z.object({ kind: z.string(), iso8601: z.string().nullable() }).strict().nullable(),
|
|
230
|
+
formula: z.object({
|
|
231
|
+
text: z.string(),
|
|
232
|
+
type: z.string().nullable(),
|
|
233
|
+
sharedIndex: z.number().int().nonnegative().nullable(),
|
|
234
|
+
reference: z.string().nullable(),
|
|
235
|
+
}).strict().nullable(),
|
|
236
|
+
style: z.object({
|
|
237
|
+
styleIndex: z.number().int().nonnegative(),
|
|
238
|
+
numberFormatId: z.number().int().nonnegative(),
|
|
239
|
+
numberFormatCode: z.string().nullable(),
|
|
240
|
+
fontId: z.number().int().nonnegative(),
|
|
241
|
+
fillId: z.number().int().nonnegative(),
|
|
242
|
+
borderId: z.number().int().nonnegative(),
|
|
243
|
+
horizontalAlignment: z.string().nullable(),
|
|
244
|
+
verticalAlignment: z.string().nullable(),
|
|
245
|
+
wrapText: z.boolean(),
|
|
246
|
+
bold: z.boolean(),
|
|
247
|
+
}).strict().nullable(),
|
|
248
|
+
richTextRuns: z.array(z.object({
|
|
249
|
+
text: z.string(),
|
|
250
|
+
fontName: z.string().nullable(),
|
|
251
|
+
color: z.string().nullable(),
|
|
252
|
+
underline: z.string().nullable(),
|
|
253
|
+
bold: z.boolean(),
|
|
254
|
+
italic: z.boolean(),
|
|
255
|
+
}).strict()).nullable(),
|
|
256
|
+
mergedRange: z.string().nullable(),
|
|
257
|
+
mergeOwner: z.string().nullable(),
|
|
258
|
+
}).strict()).max(256),
|
|
259
|
+
}).strict();
|
|
260
|
+
|
|
261
|
+
const xlsxRangeReadOutput = largeResultOutput('xlsx_read_range').extend({
|
|
262
|
+
summary: xlsxRangePageSummary,
|
|
263
|
+
content: xlsxRangePage.optional(),
|
|
264
|
+
}).strict();
|
|
265
|
+
|
|
204
266
|
const pptxInspectionSummary = z.object({
|
|
205
267
|
slideCount: z.number().int().nonnegative(),
|
|
206
268
|
masterCount: z.number().int().nonnegative(),
|
|
@@ -237,7 +299,7 @@ function docxInspectionOutput(tool) {
|
|
|
237
299
|
address: docxAddress,
|
|
238
300
|
textPreview: z.string().min(1).max(240),
|
|
239
301
|
}).strict()).max(6),
|
|
240
|
-
}).strict()
|
|
302
|
+
}).strict(),
|
|
241
303
|
}).strict();
|
|
242
304
|
}
|
|
243
305
|
|
|
@@ -248,6 +310,7 @@ const docxObjectIdentity = z.object({
|
|
|
248
310
|
textPreview: z.string().nullable(),
|
|
249
311
|
gridSpan: z.number().int().positive().nullable(),
|
|
250
312
|
verticalMerge: z.string().nullable(),
|
|
313
|
+
verticalTextAlignment: z.enum(['baseline', 'superscript', 'subscript']).nullable(),
|
|
251
314
|
}).strict();
|
|
252
315
|
|
|
253
316
|
const docxNestedObjectIdentity = docxObjectIdentity.pick({
|
|
@@ -259,6 +322,7 @@ const docxNestedObjectIdentity = docxObjectIdentity.pick({
|
|
|
259
322
|
verticalMerge: z.string().optional(),
|
|
260
323
|
verticalMergeOwner: docxAddress.optional(),
|
|
261
324
|
logicalText: z.string().optional(),
|
|
325
|
+
verticalTextAlignment: z.enum(['baseline', 'superscript', 'subscript']).optional(),
|
|
262
326
|
}).strict();
|
|
263
327
|
const docxObservationNode = z.lazy(() => z.object({
|
|
264
328
|
object: docxNestedObjectIdentity,
|
|
@@ -292,21 +356,11 @@ const docxTableIndexOutput = docxObservationOutput('docx_table_index').extend({
|
|
|
292
356
|
}).strict(),
|
|
293
357
|
tables: z.array(z.object({
|
|
294
358
|
address: docxAddress,
|
|
295
|
-
parentAddress: docxAddress.nullable(),
|
|
296
359
|
rowCount: z.number().int().nonnegative(),
|
|
297
360
|
columnCount: z.number().int().nonnegative(),
|
|
298
361
|
textPreview: z.string(),
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
address: docxAddress,
|
|
302
|
-
textPreview: z.string(),
|
|
303
|
-
textLength: z.number().int().nonnegative(),
|
|
304
|
-
}).strict().nullable(),
|
|
305
|
-
followingParagraph: z.object({
|
|
306
|
-
address: docxAddress,
|
|
307
|
-
textPreview: z.string(),
|
|
308
|
-
textLength: z.number().int().nonnegative(),
|
|
309
|
-
}).strict().nullable(),
|
|
362
|
+
precedingText: z.string().nullable(),
|
|
363
|
+
followingText: z.string().nullable(),
|
|
310
364
|
}).strict()).optional(),
|
|
311
365
|
}).strict();
|
|
312
366
|
|
|
@@ -370,7 +424,7 @@ const docxReadObjectOutput = docxObservationOutput('docx_read_object').extend({
|
|
|
370
424
|
const tools = [
|
|
371
425
|
{
|
|
372
426
|
name: 'docx_inspect',
|
|
373
|
-
description: 'Inspect one current DOCX. Set returnContent true
|
|
427
|
+
description: 'Inspect one current DOCX for identity and package overview. The response always includes a bounded identity summary. Set returnContent true when that summary is the requested direct result. Provide output to retain the complete machine observation and return its artifact receipt. These channels are independent and may be used together. At least one channel is required. Use list and read operations to traverse selected document objects in native structure order. This overview is not a complete final-document readback; use docx_export_json when a downstream consumer requires the complete body projection.',
|
|
374
428
|
inputSchema: inputContract('docx_inspect'),
|
|
375
429
|
outputSchema: docxInspectionOutput('docx_inspect'),
|
|
376
430
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
@@ -386,7 +440,7 @@ const tools = [
|
|
|
386
440
|
},
|
|
387
441
|
{
|
|
388
442
|
name: 'docx_table_index',
|
|
389
|
-
description: 'Locate tables in one current DOCX without returning full cell content or deciding table semantics. Set returnContent true to return
|
|
443
|
+
description: 'Locate tables in one current DOCX without returning full cell content or deciding table semantics. Set returnContent true to return as many compact native addresses, shapes, and short text clues as fit the bounded response; the provider chooses page size. Provide output to store the complete index and return its artifact receipt. These channels are independent and may be used together; at least one is required. Continue from receipt.nextOffset only when an unreturned table is needed for the current decision, then pass one returned address unchanged to a narrow table or object read.',
|
|
390
444
|
inputSchema: inputContract('docx_table_index'),
|
|
391
445
|
outputSchema: docxTableIndexOutput,
|
|
392
446
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
@@ -394,7 +448,7 @@ const tools = [
|
|
|
394
448
|
},
|
|
395
449
|
{
|
|
396
450
|
name: 'docx_read_object',
|
|
397
|
-
description: 'Read explicitly selected rows, cells, or paragraphs from one native DOCX. Set returnContent true to return compact requested descendants; if receipt.narrowingRequired is true, request fewer addresses or descendant kinds. Provide output to store the complete selected observation and return its artifact receipt. These channels are independent and may be used together; at least one is required. A selected cell exposes its vertical-merge owner and logical text, so a continue cell keeps its physical identity while resolving the restart cell value. Use docx_read_table for a table range.',
|
|
451
|
+
description: 'Read explicitly selected rows, cells, or paragraphs from one native DOCX. Set returnContent true to return compact requested descendants; if receipt.narrowingRequired is true, request fewer addresses or descendant kinds. Provide output to store the complete selected observation and return its artifact receipt. These channels are independent and may be used together; at least one is required. A selected cell exposes its vertical-merge owner and logical text, so a continue cell keeps its physical identity while resolving the restart cell value. Run and text descendants expose their native verticalTextAlignment when it is baseline, superscript, or subscript. Use docx_read_table for a table range.',
|
|
398
452
|
inputSchema: inputContract('docx_read_object'),
|
|
399
453
|
outputSchema: docxReadObjectOutput,
|
|
400
454
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
@@ -402,7 +456,7 @@ const tools = [
|
|
|
402
456
|
},
|
|
403
457
|
{
|
|
404
458
|
name: 'docx_read_table',
|
|
405
|
-
description: 'Read an explicit row range from exactly one table selected by native OpenXML address; it never builds another whole-table data object. Set returnContent true to return a byte-bounded compact row page. Provide output to store full paragraph and text-node detail for the selected row page and return its artifact receipt. These channels are independent and may be used together; at least one is required. Request only rows needed for the current decision; receipt.remaining is navigation information, not an obligation to read unused rows, and blank template rows need not be paged through. receipt.nextOffset is present only when another row page exists. Each returned row and cell keeps its reusable native address, zero-based logical gridColumnStart, gridSpan, vertical-merge owner, physical text, and logical text. Match columns across rows by gridColumnStart; a tc[n] path or array position is only that row\'s physical cell ordinal and is not a column identity when gridSpan or gridBefore is present. In a vertical merge, restart begins one logical cell and a continue cell is not an independent row value: logicalText resolves the restart cell value while text remains the physical cell value. Use docx_read_object when one exact object needs a narrower descendant view. The provider reports physical structure only; the Agent decides template and business meaning.',
|
|
459
|
+
description: 'Read an explicit row range from exactly one table selected by native OpenXML address; it never builds another whole-table data object. Set returnContent true to return a byte-bounded compact row page. Provide output to store full paragraph and text-node detail, including native verticalTextAlignment, for the selected row page and return its artifact receipt. These channels are independent and may be used together; at least one is required. Request only rows needed for the current decision; receipt.remaining is navigation information, not an obligation to read unused rows, and blank template rows need not be paged through. receipt.nextOffset is present only when another row page exists. Each returned row and cell keeps its reusable native address, zero-based logical gridColumnStart, gridSpan, vertical-merge owner, physical text, and logical text. Match columns across rows by gridColumnStart; a tc[n] path or array position is only that row\'s physical cell ordinal and is not a column identity when gridSpan or gridBefore is present. In a vertical merge, restart begins one logical cell and a continue cell is not an independent row value: logicalText resolves the restart cell value while text remains the physical cell value. Use docx_read_object when one exact object needs a narrower descendant view. The provider reports physical structure only; the Agent decides template and business meaning.',
|
|
406
460
|
inputSchema: inputContract('docx_read_table'),
|
|
407
461
|
outputSchema: docxTableReadOutput,
|
|
408
462
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
@@ -410,28 +464,35 @@ const tools = [
|
|
|
410
464
|
},
|
|
411
465
|
{
|
|
412
466
|
name: 'docx_replace_content_from_source',
|
|
413
|
-
description: 'Replace existing target paragraph or table-cell content from explicitly selected native source paragraphs, runs, text nodes, or exact text ranges while retaining target container formatting and table structure. Use it after docx_fill_table_from_tables when the target needs selected source
|
|
467
|
+
description: 'Replace existing target paragraph or table-cell content from explicitly selected native source cells, paragraphs, runs, text nodes, or exact text ranges while retaining target container formatting and table structure. For a source cell already returned by docx_read_table, select a Unicode-scalar range directly against its returned text; the provider retains every crossed native run, including superscript and subscript, without another descendant read. Consecutive run or text selections from one source paragraph form one target paragraph, and source paragraph boundaries remain paragraph boundaries. Use it after docx_fill_table_from_tables when the target needs selected source content instead of the whole source cell; pass returned addresses unchanged and never retype source-owned text. It does not copy source rows, cells, spans, or merges.',
|
|
414
468
|
inputSchema: inputContract('docx_replace_content_from_source'),
|
|
415
469
|
outputSchema: fixedEditOutput('docx_replace_content_from_source'),
|
|
416
470
|
handler: args => fixedEdit('docx_replace_content_from_source', args),
|
|
417
471
|
},
|
|
418
472
|
{
|
|
419
473
|
name: 'docx_set_text',
|
|
420
|
-
description: 'Replace the whole text content of paragraph or cell objects observed from this exact input DOCX while retaining target formatting, bookmarks, spans, and vertical merges. For a vertically merged logical cell, write its visible text to the restart cell rather than a continue cell. Tabs and line breaks remain native document text controls; targets containing non-text objects are rejected.
|
|
474
|
+
description: 'Replace the whole text content of paragraph or cell objects observed from this exact input DOCX while retaining target formatting, bookmarks, spans, and vertical merges. For a vertically merged logical cell, write its visible text to the restart cell rather than a continue cell. Tabs and line breaks remain native document text controls; targets containing non-text objects are rejected. Use this only for newly derived text. Content copied or selected from a source DOCX uses docx_replace_content_from_source so native runs such as superscript and subscript are retained. This does not insert objects, change table structure, copy source formatting, or decide business wording.',
|
|
421
475
|
inputSchema: inputContract('docx_set_text'),
|
|
422
476
|
outputSchema: fixedEditOutput('docx_set_text'),
|
|
423
477
|
handler: args => fixedEdit('docx_set_text', args),
|
|
424
478
|
},
|
|
479
|
+
{
|
|
480
|
+
name: 'docx_set_paragraph_pagination',
|
|
481
|
+
description: 'Set native pagination properties on explicitly selected current DOCX paragraphs. Each change sets at least one pagination property. keepWithNext keeps a paragraph with the immediately following paragraph or table but does not guarantee that a table header remains with its first body row. keepLinesTogether keeps one paragraph on one page; pageBreakBefore starts it on a new page; preventWidowOrphanLines controls isolated first or last lines. Omitted properties remain unchanged. The caller chooses paragraphs from current native addresses; the provider does not decide document layout or business meaning.',
|
|
482
|
+
inputSchema: inputContract('docx_set_paragraph_pagination'),
|
|
483
|
+
outputSchema: fixedEditOutput('docx_set_paragraph_pagination'),
|
|
484
|
+
handler: args => fixedEdit('docx_set_paragraph_pagination', args),
|
|
485
|
+
},
|
|
425
486
|
{
|
|
426
487
|
name: 'docx_set_table_body',
|
|
427
|
-
description: 'Atomically replace one exact current target-table row range while retaining the table, target styles, grid widths, and all rows and surrounding content outside the range. When retaining leading rows reported with repeatHeader=true, existingRows starts after all of them and never at a verticalMerge=continue row. Name every target grid column in native order and choose one current row inside existingRows as the style prototype for each final row. Horizontal spans use contiguous column IDs. Set rowSpan on one logical cell to occupy multiple rows and omit those columns from the covered rows; the provider writes native vertical merge cells. Every other grid column remains explicit. Every explicit cell includes an already-derived value; source-owned content is not retyped here. An empty final row array removes the range when another table row remains. The provider commits once and returns structural readback. It does not read source tables, map source to target, derive text, choose business columns, identify headers, or accept non-text cell content; use docx_fill_table_from_tables and docx_replace_content_from_source for source-owned table content.',
|
|
488
|
+
description: 'Atomically replace one exact current target-table row range while retaining the table, target styles, grid widths, and all rows and surrounding content outside the range. When retaining leading rows reported with repeatHeader=true, existingRows starts after all of them and never at a verticalMerge=continue row. Name every target grid column in native order and choose one current row inside existingRows as the style prototype for each final row. Horizontal spans use contiguous column IDs. Set rowSpan on one logical cell to occupy multiple rows and omit those columns from the covered rows; the provider writes native vertical merge cells. Set cantSplit on a final physical row when it must remain whole across page boundaries; omit it to preserve the prototype row property. Every other grid column remains explicit. Every explicit cell includes an already-derived value; source-owned content is not retyped here. An empty final row array removes the range when another table row remains. The provider commits once and returns structural readback. It does not read source tables, map source to target, derive text, choose business columns, identify headers, or accept non-text cell content; use docx_fill_table_from_tables and docx_replace_content_from_source for source-owned table content.',
|
|
428
489
|
inputSchema: inputContract('docx_set_table_body'),
|
|
429
490
|
outputSchema: fixedEditOutput('docx_set_table_body'),
|
|
430
491
|
handler: args => fixedEdit('docx_set_table_body', args),
|
|
431
492
|
},
|
|
432
493
|
{
|
|
433
494
|
name: 'docx_fill_table_from_tables',
|
|
434
|
-
description: 'Fill one current target-table body from one or more explicitly ordered current source-table row ranges. For each source, select
|
|
495
|
+
description: 'Fill one current target-table body from one or more explicitly ordered current source-table row ranges. For each source, select an unmerged record column when every physical source row must remain an output row; mapped columns still retain their native vertical merges. Select a merged record column only when every mapping into one target cell has one equal scalar value throughout that merge group. Map source grid columns onto every target prototype cell. The provider concatenates source records in declared order, copies each mapped source cell in full, preserves horizontal spans, rebuilds vertical merges only within each source range, validates the complete target grid, commits once, and returns structural readback. It does not discover source tables, choose source or target business meaning, filter records, translate or rewrite text, or apply business-specific rules. A single source uses the same sources array with one item. If a target needs only selected source descendants, such as one language from a bilingual cell, immediately use the returned target-cell addresses with docx_replace_content_from_source before releasing that source or reading back the completed target.',
|
|
435
496
|
inputSchema: inputContract('docx_fill_table_from_tables'),
|
|
436
497
|
outputSchema: fixedEditOutput('docx_fill_table_from_tables'),
|
|
437
498
|
handler: args => fixedEdit('docx_fill_table_from_tables', args),
|
|
@@ -488,7 +549,7 @@ const tools = [
|
|
|
488
549
|
},
|
|
489
550
|
{
|
|
490
551
|
name: 'docx_export_json',
|
|
491
|
-
description: 'Produce
|
|
552
|
+
description: 'Produce the complete body-only DOCX JSON projection required for final-document readback or another downstream consumer of that format. Set returnContent true to return the complete result when it fits the response limit. Provide output to write the complete result to a new JSON file. The two choices are independent and may be used together; at least one is required. This does not replace bounded list and read operations during document processing.',
|
|
492
553
|
inputSchema: inputContract('docx_export_json'),
|
|
493
554
|
outputSchema: largeResultOutput('docx_export_json'),
|
|
494
555
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
@@ -580,6 +641,14 @@ const tools = [
|
|
|
580
641
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
581
642
|
handler: xlsxExportJson,
|
|
582
643
|
},
|
|
644
|
+
{
|
|
645
|
+
name: 'xlsx_read_range',
|
|
646
|
+
description: 'Read one explicit native A1 cell or rectangular range from one current XLSX worksheet. Pages use a row-major cell offset and return physical presence, raw and formatted values, normalized value type, formula metadata, style, rich text, and merged-range ownership. The receipt always reports remaining cells and the next offset. Continue only when another selected cell is needed. Set returnContent true to return the selected page when it fits the response limit. Provide output to store the same complete selected page as an immutable artifact. These channels are independent and may be used together; at least one is required. This tool does not infer regions, headers, records, field meanings, or business mappings; convert legacy XLS before reading Open XML cells.',
|
|
647
|
+
inputSchema: inputContract('xlsx_read_range'),
|
|
648
|
+
outputSchema: xlsxRangeReadOutput,
|
|
649
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
650
|
+
handler: xlsxReadRange,
|
|
651
|
+
},
|
|
583
652
|
...fixedToolDefinitions(xlsxFixedTools),
|
|
584
653
|
{
|
|
585
654
|
name: 'xlsx_validate',
|
|
@@ -692,32 +761,17 @@ function compactDocxInspection(report) {
|
|
|
692
761
|
};
|
|
693
762
|
}
|
|
694
763
|
|
|
695
|
-
function compactDocxObjectIdentity(object) {
|
|
696
|
-
return {
|
|
697
|
-
address: object.address,
|
|
698
|
-
parentAddress: object.parentAddress,
|
|
699
|
-
kind: object.kind,
|
|
700
|
-
textPreview: object.textPreview,
|
|
701
|
-
gridSpan: object.gridSpan,
|
|
702
|
-
verticalMerge: object.verticalMerge,
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
|
|
706
764
|
function compactTableIndexEntry(table) {
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
textLength: value.textLength,
|
|
711
|
-
};
|
|
765
|
+
const paragraphText = value => value === null
|
|
766
|
+
? null
|
|
767
|
+
: value.textPreview.trim().replace(/\s+/gu, ' ').slice(0, 32);
|
|
712
768
|
return {
|
|
713
769
|
address: table.address,
|
|
714
|
-
parentAddress: table.parentAddress,
|
|
715
770
|
rowCount: table.rowCount,
|
|
716
771
|
columnCount: table.columnCount,
|
|
717
|
-
textPreview: table.textPreview.trim().replace(/\s+/gu, ' ').slice(0,
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
followingParagraph: paragraph(table.followingParagraph),
|
|
772
|
+
textPreview: table.textPreview.trim().replace(/\s+/gu, ' ').slice(0, 64),
|
|
773
|
+
precedingText: paragraphText(table.precedingParagraph),
|
|
774
|
+
followingText: paragraphText(table.followingParagraph),
|
|
721
775
|
};
|
|
722
776
|
}
|
|
723
777
|
|
|
@@ -734,6 +788,7 @@ function compactDocxObservation(observation) {
|
|
|
734
788
|
...(identity.verticalMerge === null ? {} : { verticalMerge: identity.verticalMerge }),
|
|
735
789
|
...(node.object.verticalMergeOwner === null ? {} : { verticalMergeOwner: node.object.verticalMergeOwner }),
|
|
736
790
|
...(node.object.logicalText === null ? {} : { logicalText: node.object.logicalText }),
|
|
791
|
+
...(identity.verticalTextAlignment === null ? {} : { verticalTextAlignment: identity.verticalTextAlignment }),
|
|
737
792
|
};
|
|
738
793
|
return {
|
|
739
794
|
object,
|
|
@@ -755,7 +810,7 @@ async function docxInspect(args) {
|
|
|
755
810
|
artifact: delivery.output === null
|
|
756
811
|
? null
|
|
757
812
|
: await writeIdempotentJsonArtifact(delivery.output, result.json),
|
|
758
|
-
...
|
|
813
|
+
...compactDocxInspection(result.json),
|
|
759
814
|
};
|
|
760
815
|
}
|
|
761
816
|
|
|
@@ -829,9 +884,8 @@ async function docxObservation(tool, args) {
|
|
|
829
884
|
};
|
|
830
885
|
}
|
|
831
886
|
const offset = Math.min(args.offset ?? 0, totalCount);
|
|
832
|
-
const requestedLimit = args.limit ?? totalCount;
|
|
833
887
|
const tables = [];
|
|
834
|
-
for (const sourceTable of payload.tables.slice(offset
|
|
888
|
+
for (const sourceTable of payload.tables.slice(offset)) {
|
|
835
889
|
const table = compactTableIndexEntry(sourceTable);
|
|
836
890
|
const candidate = [...tables, table];
|
|
837
891
|
if (tables.length > 0
|
|
@@ -1217,6 +1271,21 @@ async function xlsxExportJson(args) {
|
|
|
1217
1271
|
return deliverLargeJsonResult({ tool: 'xlsx_export_json', args, runtime: commandRuntime(result), payload: result.json, sourcePaths: [input] });
|
|
1218
1272
|
}
|
|
1219
1273
|
|
|
1274
|
+
async function xlsxReadRange(args) {
|
|
1275
|
+
const input = path.resolve(requireString(args.input, 'input'));
|
|
1276
|
+
return withTempJsonFile(args, async requestPath => {
|
|
1277
|
+
const result = await runJsonCandidateChain(xlsxCandidates, ['xlsx_read_range', requestPath]);
|
|
1278
|
+
return deliverLargeJsonResult({
|
|
1279
|
+
tool: 'xlsx_read_range',
|
|
1280
|
+
args,
|
|
1281
|
+
runtime: commandRuntime(result),
|
|
1282
|
+
payload: result.json,
|
|
1283
|
+
sourcePaths: [input],
|
|
1284
|
+
summary: result.json.receipt,
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1220
1289
|
async function xlsxValidate(args) {
|
|
1221
1290
|
const input = path.resolve(requireString(args.input, 'input'));
|
|
1222
1291
|
const result = await runJsonCandidateChain(xlsxCandidates, ['validate', input], { allowedExitCodes: [0, 1] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiwater/office-mcp",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.28",
|
|
4
4
|
"description": "Published MCP server for Tiwater Office document capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"_shared/large-json-result.mjs",
|
|
21
21
|
"_shared/output-write-lock.mjs",
|
|
22
22
|
"office/index.mjs",
|
|
23
|
+
"office/docx-object-identity.mjs",
|
|
23
24
|
"office/README.md",
|
|
24
25
|
"office/contracts/tiwater-office-provider-contract-manifest-v1.json",
|
|
25
26
|
"office/contracts/*.schema.json"
|