@tiwater/office-mcp 0.18.2 → 0.18.4
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_apply_font_policy.schema.json +1 -1
- package/office/contracts/docx_apply_toc_style_policy.schema.json +1 -1
- package/office/contracts/docx_copy_content.schema.json +1 -0
- package/office/contracts/docx_copy_object.schema.json +1 -0
- package/office/contracts/docx_delete_object.schema.json +1 -0
- package/office/contracts/docx_merge_cells.schema.json +1 -0
- package/office/contracts/docx_refresh_fields.schema.json +1 -1
- package/office/contracts/docx_replace_style_ids.schema.json +1 -0
- package/office/contracts/docx_replace_table_rows.schema.json +1 -0
- package/office/contracts/docx_set_text.schema.json +1 -0
- package/office/contracts/docx_split_cells.schema.json +1 -0
- package/office/contracts/docx_strip_direct_formatting.schema.json +1 -0
- package/office/contracts/docx_table_index.schema.json +21 -0
- package/office/contracts/tiwater-office-provider-contract-manifest-v1.json +36 -25
- package/office/index.mjs +54 -13
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"x-tiwater-file-role": "read",
|
|
11
11
|
"description": "Path to the current caller-authorized tiwater.docx-font-policy/v1 JSON asset."
|
|
12
12
|
},
|
|
13
|
-
"output": { "type": "string", "minLength": 1, "x-tiwater-file-role": "write" },
|
|
13
|
+
"output": { "type": "string", "minLength": 1, "description": "Output DOCX path; may equal input for an atomic in-place update.", "x-tiwater-file-role": "write" },
|
|
14
14
|
"receiptOutput": {
|
|
15
15
|
"type": "string",
|
|
16
16
|
"minLength": 1,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"input": { "type": "string", "minLength": 1, "x-tiwater-file-role": "read" },
|
|
7
7
|
"italic": { "type": "boolean" },
|
|
8
8
|
"indentCharactersPerLevel": { "type": "integer", "minimum": 0, "maximum": 21474836 },
|
|
9
|
-
"output": { "type": "string", "minLength": 1, "x-tiwater-file-role": "write" },
|
|
9
|
+
"output": { "type": "string", "minLength": 1, "description": "Output DOCX path; may equal input for an atomic in-place update.", "x-tiwater-file-role": "write" },
|
|
10
10
|
"receiptOutput": {
|
|
11
11
|
"type": "string",
|
|
12
12
|
"minLength": 1,
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"output": {
|
|
12
12
|
"type": "string",
|
|
13
13
|
"minLength": 1,
|
|
14
|
-
"description": "
|
|
14
|
+
"description": "Output DOCX path; may equal input for an atomic in-place update.",
|
|
15
15
|
"x-tiwater-file-role": "write"
|
|
16
16
|
},
|
|
17
17
|
"receiptOutput": {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "tiwater.office-mcp-input/docx_table_index/v1",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"input": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"minLength": 1,
|
|
9
|
+
"description": "Current DOCX path.",
|
|
10
|
+
"x-tiwater-file-role": "read"
|
|
11
|
+
},
|
|
12
|
+
"output": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"minLength": 1,
|
|
15
|
+
"description": "New JSON artifact path for the complete table index.",
|
|
16
|
+
"x-tiwater-file-role": "write"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["input", "output"],
|
|
20
|
+
"additionalProperties": false
|
|
21
|
+
}
|
|
@@ -2,29 +2,29 @@
|
|
|
2
2
|
"schema": "tiwater.office-provider-contract-manifest/v1",
|
|
3
3
|
"provider": {
|
|
4
4
|
"id": "@tiwater/office-mcp",
|
|
5
|
-
"version": "0.18.
|
|
5
|
+
"version": "0.18.4"
|
|
6
6
|
},
|
|
7
7
|
"tools": [
|
|
8
8
|
{
|
|
9
9
|
"name": "docx_apply_font_policy",
|
|
10
10
|
"providerContract": {
|
|
11
11
|
"source": "packages/docx-cli/contracts/mcp-input/docx_apply_font_policy.schema.json",
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "0df423bca745d196923086d3ff9e5b20be59303460dbb54d5a367cfd701e03d3"
|
|
13
13
|
},
|
|
14
14
|
"inputContract": {
|
|
15
15
|
"path": "office/contracts/docx_apply_font_policy.schema.json",
|
|
16
|
-
"sha256": "
|
|
16
|
+
"sha256": "0df423bca745d196923086d3ff9e5b20be59303460dbb54d5a367cfd701e03d3"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"name": "docx_apply_toc_style_policy",
|
|
21
21
|
"providerContract": {
|
|
22
22
|
"source": "packages/docx-cli/contracts/mcp-input/docx_apply_toc_style_policy.schema.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "bd912b9c2442ad2528ae5411a4399bb02ea5a44d5d64ed4a87e212d6d7b57dc2"
|
|
24
24
|
},
|
|
25
25
|
"inputContract": {
|
|
26
26
|
"path": "office/contracts/docx_apply_toc_style_policy.schema.json",
|
|
27
|
-
"sha256": "
|
|
27
|
+
"sha256": "bd912b9c2442ad2528ae5411a4399bb02ea5a44d5d64ed4a87e212d6d7b57dc2"
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
{
|
|
@@ -42,33 +42,33 @@
|
|
|
42
42
|
"name": "docx_copy_content",
|
|
43
43
|
"providerContract": {
|
|
44
44
|
"source": "packages/docx-cli/contracts/mcp-input/docx_copy_content.schema.json",
|
|
45
|
-
"sha256": "
|
|
45
|
+
"sha256": "a7b4998f8c9f6423c6d6ca5953d4b8ca5572f38dfdc23bcc06c20c7c488af727"
|
|
46
46
|
},
|
|
47
47
|
"inputContract": {
|
|
48
48
|
"path": "office/contracts/docx_copy_content.schema.json",
|
|
49
|
-
"sha256": "
|
|
49
|
+
"sha256": "a7b4998f8c9f6423c6d6ca5953d4b8ca5572f38dfdc23bcc06c20c7c488af727"
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"name": "docx_copy_object",
|
|
54
54
|
"providerContract": {
|
|
55
55
|
"source": "packages/docx-cli/contracts/mcp-input/docx_copy_object.schema.json",
|
|
56
|
-
"sha256": "
|
|
56
|
+
"sha256": "f5ebb6c59a2bcb82e0504ab517505fe7525e905ff71bd9dea817967e79cee7a3"
|
|
57
57
|
},
|
|
58
58
|
"inputContract": {
|
|
59
59
|
"path": "office/contracts/docx_copy_object.schema.json",
|
|
60
|
-
"sha256": "
|
|
60
|
+
"sha256": "f5ebb6c59a2bcb82e0504ab517505fe7525e905ff71bd9dea817967e79cee7a3"
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
"name": "docx_delete_object",
|
|
65
65
|
"providerContract": {
|
|
66
66
|
"source": "packages/docx-cli/contracts/mcp-input/docx_delete_object.schema.json",
|
|
67
|
-
"sha256": "
|
|
67
|
+
"sha256": "4497eb24df0e5631601232a8b35a9eddf914d02146992dd22f1cfba93ef7780f"
|
|
68
68
|
},
|
|
69
69
|
"inputContract": {
|
|
70
70
|
"path": "office/contracts/docx_delete_object.schema.json",
|
|
71
|
-
"sha256": "
|
|
71
|
+
"sha256": "4497eb24df0e5631601232a8b35a9eddf914d02146992dd22f1cfba93ef7780f"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
{
|
|
@@ -108,11 +108,11 @@
|
|
|
108
108
|
"name": "docx_merge_cells",
|
|
109
109
|
"providerContract": {
|
|
110
110
|
"source": "packages/docx-cli/contracts/mcp-input/docx_merge_cells.schema.json",
|
|
111
|
-
"sha256": "
|
|
111
|
+
"sha256": "2106f2b2a39f47fb766e43bcb9a6e586827b3f31a079d875b6cc5c647d253dd4"
|
|
112
112
|
},
|
|
113
113
|
"inputContract": {
|
|
114
114
|
"path": "office/contracts/docx_merge_cells.schema.json",
|
|
115
|
-
"sha256": "
|
|
115
|
+
"sha256": "2106f2b2a39f47fb766e43bcb9a6e586827b3f31a079d875b6cc5c647d253dd4"
|
|
116
116
|
}
|
|
117
117
|
},
|
|
118
118
|
{
|
|
@@ -130,66 +130,77 @@
|
|
|
130
130
|
"name": "docx_refresh_fields",
|
|
131
131
|
"providerContract": {
|
|
132
132
|
"source": "packages/convert-cli/schemas/mcp-input/docx_refresh_fields.schema.json",
|
|
133
|
-
"sha256": "
|
|
133
|
+
"sha256": "8f2f8694b6d533d7f48b6e1e0c82be3a9c5aac55c50dba00daadd0ea0a76a8a7"
|
|
134
134
|
},
|
|
135
135
|
"inputContract": {
|
|
136
136
|
"path": "office/contracts/docx_refresh_fields.schema.json",
|
|
137
|
-
"sha256": "
|
|
137
|
+
"sha256": "8f2f8694b6d533d7f48b6e1e0c82be3a9c5aac55c50dba00daadd0ea0a76a8a7"
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"name": "docx_replace_style_ids",
|
|
142
142
|
"providerContract": {
|
|
143
143
|
"source": "packages/docx-cli/contracts/mcp-input/docx_replace_style_ids.schema.json",
|
|
144
|
-
"sha256": "
|
|
144
|
+
"sha256": "25f4d4e7c69fa5a2c4a82621aa58ea8eda21245636f84f2243ca4e9092616b68"
|
|
145
145
|
},
|
|
146
146
|
"inputContract": {
|
|
147
147
|
"path": "office/contracts/docx_replace_style_ids.schema.json",
|
|
148
|
-
"sha256": "
|
|
148
|
+
"sha256": "25f4d4e7c69fa5a2c4a82621aa58ea8eda21245636f84f2243ca4e9092616b68"
|
|
149
149
|
}
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
152
|
"name": "docx_replace_table_rows",
|
|
153
153
|
"providerContract": {
|
|
154
154
|
"source": "packages/docx-cli/contracts/mcp-input/docx_replace_table_rows.schema.json",
|
|
155
|
-
"sha256": "
|
|
155
|
+
"sha256": "02ce941414496ddffa7d531ca6fa982598f607b516d990d598ace521d725cdf6"
|
|
156
156
|
},
|
|
157
157
|
"inputContract": {
|
|
158
158
|
"path": "office/contracts/docx_replace_table_rows.schema.json",
|
|
159
|
-
"sha256": "
|
|
159
|
+
"sha256": "02ce941414496ddffa7d531ca6fa982598f607b516d990d598ace521d725cdf6"
|
|
160
160
|
}
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
"name": "docx_set_text",
|
|
164
164
|
"providerContract": {
|
|
165
165
|
"source": "packages/docx-cli/contracts/mcp-input/docx_set_text.schema.json",
|
|
166
|
-
"sha256": "
|
|
166
|
+
"sha256": "9feca848acff5ff7c0f2e08f618e183494959b5a74e9e37e06086d7a627810ca"
|
|
167
167
|
},
|
|
168
168
|
"inputContract": {
|
|
169
169
|
"path": "office/contracts/docx_set_text.schema.json",
|
|
170
|
-
"sha256": "
|
|
170
|
+
"sha256": "9feca848acff5ff7c0f2e08f618e183494959b5a74e9e37e06086d7a627810ca"
|
|
171
171
|
}
|
|
172
172
|
},
|
|
173
173
|
{
|
|
174
174
|
"name": "docx_split_cells",
|
|
175
175
|
"providerContract": {
|
|
176
176
|
"source": "packages/docx-cli/contracts/mcp-input/docx_split_cells.schema.json",
|
|
177
|
-
"sha256": "
|
|
177
|
+
"sha256": "085a5b8e924c68958752eeb2de9644a3084c249408e9f135ee936f14e9ce5f9b"
|
|
178
178
|
},
|
|
179
179
|
"inputContract": {
|
|
180
180
|
"path": "office/contracts/docx_split_cells.schema.json",
|
|
181
|
-
"sha256": "
|
|
181
|
+
"sha256": "085a5b8e924c68958752eeb2de9644a3084c249408e9f135ee936f14e9ce5f9b"
|
|
182
182
|
}
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
"name": "docx_strip_direct_formatting",
|
|
186
186
|
"providerContract": {
|
|
187
187
|
"source": "packages/docx-cli/contracts/mcp-input/docx_strip_direct_formatting.schema.json",
|
|
188
|
-
"sha256": "
|
|
188
|
+
"sha256": "4931d4432c574154eb7a344ee4dc485d99d8840c07d2e46f647e14490cbeedae"
|
|
189
189
|
},
|
|
190
190
|
"inputContract": {
|
|
191
191
|
"path": "office/contracts/docx_strip_direct_formatting.schema.json",
|
|
192
|
-
"sha256": "
|
|
192
|
+
"sha256": "4931d4432c574154eb7a344ee4dc485d99d8840c07d2e46f647e14490cbeedae"
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "docx_table_index",
|
|
197
|
+
"providerContract": {
|
|
198
|
+
"source": "packages/docx-cli/contracts/mcp-input/docx_table_index.schema.json",
|
|
199
|
+
"sha256": "7549ce28e3cc51ae17cd86c77c97698b6e90f0125afd34ae8831fde7f87ddf67"
|
|
200
|
+
},
|
|
201
|
+
"inputContract": {
|
|
202
|
+
"path": "office/contracts/docx_table_index.schema.json",
|
|
203
|
+
"sha256": "7549ce28e3cc51ae17cd86c77c97698b6e90f0125afd34ae8831fde7f87ddf67"
|
|
193
204
|
}
|
|
194
205
|
},
|
|
195
206
|
{
|
package/office/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { createReadStream } from 'node:fs';
|
|
4
|
-
import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { isDeepStrictEqual } from 'node:util';
|
|
7
7
|
import { McpServer } from '@modelcontextprotocol/server';
|
|
@@ -216,6 +216,18 @@ const docxListObjectsOutput = artifactOutput('docx_list_objects').extend({
|
|
|
216
216
|
runtime: runtimeIdentity,
|
|
217
217
|
}).strict();
|
|
218
218
|
|
|
219
|
+
const docxTableIndexOutput = artifactOutput('docx_table_index').extend({
|
|
220
|
+
schema: z.literal('tiwater.docx-table-index/v1'),
|
|
221
|
+
tables: z.array(z.object({
|
|
222
|
+
address: docxAddress,
|
|
223
|
+
parentAddress: docxAddress.nullable(),
|
|
224
|
+
rowCount: z.number().int().nonnegative(),
|
|
225
|
+
columnCount: z.number().int().nonnegative(),
|
|
226
|
+
textPreview: z.string(),
|
|
227
|
+
textLength: z.number().int().nonnegative(),
|
|
228
|
+
}).strict()),
|
|
229
|
+
}).strict();
|
|
230
|
+
|
|
219
231
|
const docxReadObjectOutput = artifactOutput('docx_read_object').extend({
|
|
220
232
|
observations: z.array(docxObservationNode).min(1),
|
|
221
233
|
}).strict();
|
|
@@ -237,6 +249,14 @@ const tools = [
|
|
|
237
249
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
238
250
|
handler: args => docxObservation('docx_list_objects', args),
|
|
239
251
|
},
|
|
252
|
+
{
|
|
253
|
+
name: 'docx_table_index',
|
|
254
|
+
description: 'List every table in one current DOCX as a compact native index with its OpenXML address, row count, column count, and short text preview. Use it to choose a table and confirm its shape before listing rows or reading selected content. It does not return full cell content or decide table semantics.',
|
|
255
|
+
inputSchema: inputContract('docx_table_index'),
|
|
256
|
+
outputSchema: docxTableIndexOutput,
|
|
257
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
258
|
+
handler: args => docxObservation('docx_table_index', args),
|
|
259
|
+
},
|
|
240
260
|
{
|
|
241
261
|
name: 'docx_read_object',
|
|
242
262
|
description: 'Read selected tables, rows, cells, or paragraphs from one native DOCX in one call and return them in address order. Pass the document path once and only the OpenXML addresses needed for the current target. For exact inline content, use an observed cell or paragraph address and request run or text.',
|
|
@@ -559,6 +579,7 @@ async function docxObservation(tool, args) {
|
|
|
559
579
|
if (tool === 'docx_list_objects') {
|
|
560
580
|
return { ...retained, ...payload, objects: payload.objects.map(compactDocxObjectIdentity) };
|
|
561
581
|
}
|
|
582
|
+
if (tool === 'docx_table_index') return { ...retained, ...payload };
|
|
562
583
|
throw new Error(`unsupported-docx-observation-tool:${tool}`);
|
|
563
584
|
});
|
|
564
585
|
}
|
|
@@ -610,34 +631,39 @@ async function docxRefreshFields(args) {
|
|
|
610
631
|
const input = path.resolve(requireString(args.input, 'input'));
|
|
611
632
|
const output = path.resolve(requireString(args.output, 'output'));
|
|
612
633
|
const receiptOutput = path.resolve(requireString(args.receiptOutput, 'receiptOutput'));
|
|
634
|
+
const inPlace = input === output;
|
|
635
|
+
const invocationOutput = inPlace ? temporarySibling(output) : output;
|
|
613
636
|
if (path.extname(input).toLowerCase() !== '.docx' || path.extname(output).toLowerCase() !== '.docx') {
|
|
614
637
|
throw Object.assign(new Error('DOCX field refresh requires .docx input and output'), { code: -32602 });
|
|
615
638
|
}
|
|
616
|
-
await requireNewFile(output, 'output');
|
|
639
|
+
if (!inPlace) await requireNewFile(output, 'output');
|
|
617
640
|
await requireNewFile(receiptOutput, 'receiptOutput');
|
|
618
641
|
const inputArtifact = await fileArtifact(input);
|
|
619
642
|
try {
|
|
620
|
-
const result = await runJsonCandidateChain(convertCandidates, ['refresh-docx-fields', input,
|
|
643
|
+
const result = await runJsonCandidateChain(convertCandidates, ['refresh-docx-fields', input, invocationOutput]);
|
|
621
644
|
const providerReceipt = docxFieldRefreshReceipt.parse(result.json);
|
|
622
|
-
const
|
|
645
|
+
const invocationArtifact = await fileArtifact(invocationOutput);
|
|
623
646
|
if (path.resolve(providerReceipt.input) !== input
|
|
624
|
-
|| path.resolve(providerReceipt.output) !==
|
|
647
|
+
|| path.resolve(providerReceipt.output) !== invocationOutput
|
|
625
648
|
|| providerReceipt.input_sha256 !== inputArtifact.sha256
|
|
626
|
-
|| providerReceipt.output_sha256 !==
|
|
649
|
+
|| providerReceipt.output_sha256 !== invocationArtifact.sha256) {
|
|
627
650
|
throw new Error('DOCX field refresh receipt is not bound to the current input and output');
|
|
628
651
|
}
|
|
652
|
+
if (inPlace) await rename(invocationOutput, output);
|
|
653
|
+
const outputArtifact = await fileArtifact(output);
|
|
654
|
+
const acceptedReceipt = { ...providerReceipt, output, output_sha256: outputArtifact.sha256 };
|
|
629
655
|
return {
|
|
630
656
|
tool: 'docx_refresh_fields',
|
|
631
657
|
runtime: commandRuntime(result),
|
|
632
658
|
output: outputArtifact,
|
|
633
|
-
receipt: await writeJsonArtifact(receiptOutput,
|
|
659
|
+
receipt: await writeJsonArtifact(receiptOutput, acceptedReceipt),
|
|
634
660
|
summary: {
|
|
635
661
|
backend: providerReceipt.backend,
|
|
636
662
|
refreshScope: providerReceipt.refresh_scope,
|
|
637
663
|
},
|
|
638
664
|
};
|
|
639
665
|
} catch (error) {
|
|
640
|
-
await rm(
|
|
666
|
+
await rm(invocationOutput, { force: true });
|
|
641
667
|
throw error;
|
|
642
668
|
}
|
|
643
669
|
}
|
|
@@ -645,15 +671,24 @@ async function docxRefreshFields(args) {
|
|
|
645
671
|
async function copyTransform(tool, candidates, command, args, suffix = []) {
|
|
646
672
|
const input = path.resolve(requireString(args.input, 'input'));
|
|
647
673
|
const output = path.resolve(requireString(args.output, 'output'));
|
|
648
|
-
|
|
649
|
-
const
|
|
650
|
-
|
|
674
|
+
const inPlace = input === output;
|
|
675
|
+
const invocationOutput = inPlace ? temporarySibling(output) : output;
|
|
676
|
+
if (!inPlace) await requireNewFile(output, 'output');
|
|
677
|
+
try {
|
|
678
|
+
const result = await runCandidateChain(candidates, [...command, input, invocationOutput, ...suffix]);
|
|
679
|
+
if (inPlace) await rename(invocationOutput, output);
|
|
680
|
+
return { tool, runtime: commandRuntime(result), output: await fileArtifact(output) };
|
|
681
|
+
} catch (error) {
|
|
682
|
+
await rm(invocationOutput, { force: true });
|
|
683
|
+
throw error;
|
|
684
|
+
}
|
|
651
685
|
}
|
|
652
686
|
|
|
653
687
|
async function fixedEdit(tool, args) {
|
|
688
|
+
const input = path.resolve(requireString(args.input, 'input'));
|
|
654
689
|
const output = path.resolve(requireString(args.output, 'output'));
|
|
655
690
|
const receiptOutput = path.resolve(requireString(args.receiptOutput, 'receiptOutput'));
|
|
656
|
-
await requireNewFile(output, 'output');
|
|
691
|
+
if (!(tool.startsWith('docx_') && input === output)) await requireNewFile(output, 'output');
|
|
657
692
|
await requireNewFile(receiptOutput, 'receiptOutput');
|
|
658
693
|
const candidates = tool.startsWith('docx_') ? docxCandidates
|
|
659
694
|
: tool.startsWith('xlsx_') ? xlsxCandidates
|
|
@@ -880,6 +915,12 @@ async function requireNewFile(filePath, label) {
|
|
|
880
915
|
throw Object.assign(new Error(`${label} already exists: ${filePath}`), { code: -32602 });
|
|
881
916
|
}
|
|
882
917
|
|
|
918
|
+
function temporarySibling(filePath) {
|
|
919
|
+
const extension = path.extname(filePath);
|
|
920
|
+
const stem = path.basename(filePath, extension);
|
|
921
|
+
return path.join(path.dirname(filePath), `.${stem}.${randomUUID()}.tmp${extension}`);
|
|
922
|
+
}
|
|
923
|
+
|
|
883
924
|
function commandRuntime(result) {
|
|
884
925
|
return {
|
|
885
926
|
command: result.command,
|