@tiwater/office-mcp 0.21.45 → 0.21.47

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.
@@ -106,6 +106,12 @@
106
106
  "additionalProperties": false
107
107
  }
108
108
  },
109
+ "changesInput": {
110
+ "type": "string",
111
+ "minLength": 1,
112
+ "description": "Absolute path to a JSON file containing the same non-empty changes array accepted by changes. Use this for large batches so the array stays out of the tool call.",
113
+ "x-tiwater-file-role": "read"
114
+ },
109
115
  "output": {
110
116
  "type": "string",
111
117
  "minLength": 1,
@@ -122,7 +128,6 @@
122
128
  },
123
129
  "required": [
124
130
  "input",
125
- "changes",
126
131
  "output",
127
132
  "receiptOutput"
128
133
  ],
@@ -93,9 +93,15 @@
93
93
  }, "required": ["prototypeRow", "cells"], "additionalProperties": false
94
94
  }
95
95
  },
96
+ "tableInput": {
97
+ "type": "string",
98
+ "minLength": 1,
99
+ "description": "Absolute path to a JSON file containing exactly table, existingRows, columns, and rows. Use this for a large table replacement so its structure and content stay out of the tool call.",
100
+ "x-tiwater-file-role": "read"
101
+ },
96
102
  "output": { "type": "string", "minLength": 1, "description": "Output DOCX path; may equal input for one atomic in-place update.", "x-tiwater-file-role": "write" },
97
103
  "receiptOutput": { "type": "string", "minLength": 1, "x-tiwater-file-role": "write", "x-tiwater-file-effect": false }
98
104
  },
99
- "required": ["input", "table", "existingRows", "columns", "rows", "output", "receiptOutput"],
105
+ "required": ["input", "output", "receiptOutput"],
100
106
  "additionalProperties": false
101
107
  }
@@ -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.45"
5
+ "version": "0.21.47"
6
6
  },
7
7
  "tools": [
8
8
  {
@@ -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": "9e739afeeda64a6014f180f97667402e98a4b0c8a79a182d6a6ef7a1c5f31cff"
177
+ "sha256": "91f021a7a848778adaffdbf338524d8a94b5593665be064edc17bd09f94ccafa"
178
178
  },
179
179
  "inputContract": {
180
180
  "path": "office/contracts/docx_replace_content_from_source.schema.json",
181
- "sha256": "9e739afeeda64a6014f180f97667402e98a4b0c8a79a182d6a6ef7a1c5f31cff"
181
+ "sha256": "91f021a7a848778adaffdbf338524d8a94b5593665be064edc17bd09f94ccafa"
182
182
  }
183
183
  },
184
184
  {
@@ -207,11 +207,11 @@
207
207
  "name": "docx_set_table",
208
208
  "providerContract": {
209
209
  "source": "packages/docx-cli/contracts/mcp-input/docx_set_table.schema.json",
210
- "sha256": "d9a9f09ee3ca13764120bcf58e501a3edc508333b01aa4e6d299db8ba7bf2834"
210
+ "sha256": "d04c40174ce3427689c970b26dd3a282f9d9f6889e4c5ac737eca5926ef709b9"
211
211
  },
212
212
  "inputContract": {
213
213
  "path": "office/contracts/docx_set_table.schema.json",
214
- "sha256": "d9a9f09ee3ca13764120bcf58e501a3edc508333b01aa4e6d299db8ba7bf2834"
214
+ "sha256": "d04c40174ce3427689c970b26dd3a282f9d9f6889e4c5ac737eca5926ef709b9"
215
215
  }
216
216
  },
217
217
  {
@@ -0,0 +1,22 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ export async function resolveFileBackedChanges(args) {
5
+ const hasInline = Array.isArray(args?.changes);
6
+ const hasFile = typeof args?.changesInput === 'string' && args.changesInput.trim().length > 0;
7
+ if (!hasInline && !hasFile) throw new Error('provide-changes-or-changesInput');
8
+ if (hasInline && !hasFile) return args;
9
+
10
+ let changes;
11
+ try {
12
+ changes = JSON.parse(await readFile(path.resolve(args.changesInput), 'utf8'));
13
+ } catch (error) {
14
+ throw new Error(`changesInput-invalid: ${error.message}`);
15
+ }
16
+ if (!Array.isArray(changes) || changes.length === 0) {
17
+ throw new Error('changesInput-must-contain-non-empty-json-array');
18
+ }
19
+ const resolved = { ...args, changes: hasInline ? [...args.changes, ...changes] : changes };
20
+ delete resolved.changesInput;
21
+ return resolved;
22
+ }
@@ -0,0 +1,31 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ const tableFields = ['table', 'existingRows', 'columns', 'rows'];
5
+
6
+ function hasInlineTable(args) {
7
+ return tableFields.every((field) => args?.[field] !== undefined);
8
+ }
9
+
10
+ export async function resolveFileBackedTable(args) {
11
+ const hasInline = hasInlineTable(args);
12
+ const hasFile = typeof args?.tableInput === 'string' && args.tableInput.trim().length > 0;
13
+ if (!hasInline && !hasFile) throw new Error('provide-inline-table-or-tableInput');
14
+ if (hasInline && hasFile) throw new Error('provide-only-one-table-input');
15
+ if (hasInline) return args;
16
+
17
+ let tableRequest;
18
+ try {
19
+ tableRequest = JSON.parse(await readFile(path.resolve(args.tableInput), 'utf8'));
20
+ } catch (error) {
21
+ throw new Error(`tableInput-invalid: ${error.message}`);
22
+ }
23
+ if (!tableRequest || typeof tableRequest !== 'object' || Array.isArray(tableRequest)
24
+ || !tableFields.every((field) => tableRequest[field] !== undefined)
25
+ || Object.keys(tableRequest).some((field) => !tableFields.includes(field))) {
26
+ throw new Error('tableInput-must-contain-table-existingRows-columns-and-rows');
27
+ }
28
+ const resolved = { ...args, ...tableRequest };
29
+ delete resolved.tableInput;
30
+ return resolved;
31
+ }
package/office/index.mjs CHANGED
@@ -30,6 +30,8 @@ import {
30
30
  effectKindMetadata,
31
31
  } from '../_shared/effect-kind.mjs';
32
32
  import { compactDocxObjectIdentity } from './docx-object-identity.mjs';
33
+ import { resolveFileBackedChanges } from './file-backed-changes.mjs';
34
+ import { resolveFileBackedTable } from './file-backed-table.mjs';
33
35
 
34
36
  const packageMetadata = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
35
37
  const inputContractManifest = JSON.parse(await readFile(
@@ -591,10 +593,10 @@ const tools = [
591
593
  {
592
594
  name: 'docx_replace_content_from_source',
593
595
  effectKind: 'document-mutation',
594
- description: 'Atomically replace one or more existing target paragraphs or cells with exactly the selected native source content. Select source cells, paragraphs, runs, text nodes, or Unicode-scalar text ranges; omitted content is omitted, while selected runs retain superscript, subscript, formulas, numbers, units, and symbols. This tool does not change table rows, spans, or merges.',
596
+ description: 'Atomically replace one or more existing target paragraphs or cells with exactly the selected native source content. Pass small batches in changes or keep a large batch out of the tool call by putting the same changes array in changesInput. Select source cells, paragraphs, runs, text nodes, or Unicode-scalar text ranges; omitted content is omitted, while selected runs retain superscript, subscript, formulas, numbers, units, and symbols. This tool does not change table rows, spans, or merges.',
595
597
  inputSchema: inputContract('docx_replace_content_from_source'),
596
598
  outputSchema: fixedEditOutput('docx_replace_content_from_source'),
597
- handler: (args, tool) => fixedEdit(tool, args, docxCandidates),
599
+ handler: async (args, tool) => fixedEdit(tool, await resolveFileBackedChanges(args), docxCandidates),
598
600
  },
599
601
  {
600
602
  name: 'docx_set_text',
@@ -618,7 +620,7 @@ const tools = [
618
620
  description: 'Atomically replace one exact current target-table row range with a fully specified table body. Name every target grid column in native order. Every rows[] item must contain its own prototypeRow; there is no table-level prototypeRow. Every cell must contain text: use a string for derived plain text, or null together with sourceInput and exact native sourceSelections. Each explicit cell occupies contiguous columns and may span logical rows; covered columns are omitted from following rows. Native source selections retain run formatting such as superscript and subscript. The provider retains the target table, target cell styles, grid widths, and all content outside the replaced range, and exposes no intermediate document. It does not select source rows, map business columns, infer target shape, derive wording, or copy a source table wholesale.',
619
621
  inputSchema: inputContract('docx_set_table'),
620
622
  outputSchema: fixedEditOutput('docx_set_table'),
621
- handler: (args, tool) => fixedEdit(tool, args, docxCandidates),
623
+ handler: async (args, tool) => fixedEdit(tool, await resolveFileBackedTable(args), docxCandidates),
622
624
  },
623
625
  {
624
626
  name: 'docx_insert_objects',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiwater/office-mcp",
3
- "version": "0.21.45",
3
+ "version": "0.21.47",
4
4
  "description": "Published MCP distribution for independent Tiwater Office, PDF, and Text document capabilities",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,6 +26,8 @@
26
26
  "_shared/effect-kind.mjs",
27
27
  "office/index.mjs",
28
28
  "office/docx-object-identity.mjs",
29
+ "office/file-backed-changes.mjs",
30
+ "office/file-backed-table.mjs",
29
31
  "office/README.md",
30
32
  "office/contracts/tiwater-office-provider-contract-manifest-v1.json",
31
33
  "office/contracts/*.schema.json",
@@ -2,7 +2,7 @@
2
2
  "schema": "tiwater.pdf-provider-contract-manifest/v1",
3
3
  "provider": {
4
4
  "id": "@tiwater/office-mcp",
5
- "version": "0.21.45"
5
+ "version": "0.21.47"
6
6
  },
7
7
  "runtime": {
8
8
  "command": "tiwater-pdf"
@@ -2,7 +2,7 @@
2
2
  "schema": "tiwater.text-provider-contract-manifest/v1",
3
3
  "provider": {
4
4
  "id": "@tiwater/office-mcp",
5
- "version": "0.21.45"
5
+ "version": "0.21.47"
6
6
  },
7
7
  "tools": [
8
8
  {