@tiwater/office-mcp 0.4.0 → 0.5.0
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/README.md +1 -0
- package/office/index.mjs +110 -1
- package/package.json +1 -1
package/office/README.md
CHANGED
package/office/index.mjs
CHANGED
|
@@ -100,7 +100,17 @@ const migrationCatalog = z.object({
|
|
|
100
100
|
baselineSha256: z.string(),
|
|
101
101
|
sources: z.array(migrationChoiceOutput),
|
|
102
102
|
targets: z.array(migrationChoiceOutput),
|
|
103
|
-
}).strict()
|
|
103
|
+
}).strict().superRefine((catalog, context) => {
|
|
104
|
+
for (const key of ['sources', 'targets']) {
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
for (const [index, choice] of catalog[key].entries()) {
|
|
107
|
+
if (seen.has(choice.id)) {
|
|
108
|
+
context.addIssue({ code: 'custom', path: [key, index, 'id'], message: `duplicate ${key} choice id: ${choice.id}` });
|
|
109
|
+
}
|
|
110
|
+
seen.add(choice.id);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
104
114
|
|
|
105
115
|
const migrationReceipt = z.object({
|
|
106
116
|
schema: z.string(),
|
|
@@ -139,6 +149,41 @@ const migrationCatalogOutput = z.object({
|
|
|
139
149
|
}).strict(),
|
|
140
150
|
}).strict();
|
|
141
151
|
|
|
152
|
+
const migrationQueryPage = z.object({
|
|
153
|
+
offset: z.number().int().nonnegative(),
|
|
154
|
+
returned: z.number().int().nonnegative(),
|
|
155
|
+
total: z.number().int().nonnegative(),
|
|
156
|
+
hasMore: z.boolean(),
|
|
157
|
+
}).strict();
|
|
158
|
+
|
|
159
|
+
const migrationChoiceQueryInput = z.discriminatedUnion('view', [
|
|
160
|
+
z.object({
|
|
161
|
+
catalog: pathInput.describe('Path returned by docx_list_migration_choices.'),
|
|
162
|
+
view: z.literal('sources'),
|
|
163
|
+
offset: z.number().int().nonnegative().optional(),
|
|
164
|
+
limit: z.number().int().min(1).max(10).optional(),
|
|
165
|
+
}).strict(),
|
|
166
|
+
z.object({
|
|
167
|
+
catalog: pathInput.describe('Path returned by docx_list_migration_choices.'),
|
|
168
|
+
view: z.literal('targets'),
|
|
169
|
+
sourceChoiceId: z.string().trim().min(1),
|
|
170
|
+
text: z.string().trim().min(1).optional().describe('Literal case-insensitive text to find in target text or visible context.'),
|
|
171
|
+
kinds: z.array(z.string().trim().min(1)).min(1).optional(),
|
|
172
|
+
scopes: z.array(z.string().trim().min(1)).min(1).optional(),
|
|
173
|
+
offset: z.number().int().nonnegative().optional(),
|
|
174
|
+
limit: z.number().int().min(1).max(10).optional(),
|
|
175
|
+
}).strict(),
|
|
176
|
+
]);
|
|
177
|
+
|
|
178
|
+
const migrationChoiceQueryOutput = z.object({
|
|
179
|
+
tool: z.literal('docx_query_migration_choices'),
|
|
180
|
+
catalogSha256: z.string().regex(/^[0-9a-f]{64}$/),
|
|
181
|
+
view: z.enum(['sources', 'targets']),
|
|
182
|
+
source: migrationChoiceOutput.nullable(),
|
|
183
|
+
items: z.array(migrationChoiceOutput),
|
|
184
|
+
page: migrationQueryPage,
|
|
185
|
+
}).strict();
|
|
186
|
+
|
|
142
187
|
function migrationReceiptOutput(tool) {
|
|
143
188
|
return z.object({
|
|
144
189
|
tool: z.literal(tool),
|
|
@@ -181,6 +226,14 @@ const tools = [
|
|
|
181
226
|
outputSchema: migrationCatalogOutput,
|
|
182
227
|
handler: docxListMigrationChoices,
|
|
183
228
|
},
|
|
229
|
+
{
|
|
230
|
+
name: 'docx_query_migration_choices',
|
|
231
|
+
description: 'Read one bounded page from a migration-choice catalog. List source choices, or inspect targets for one source using literal text, kind, and scope filters. This tool does not recommend or make a business choice.',
|
|
232
|
+
inputSchema: migrationChoiceQueryInput,
|
|
233
|
+
outputSchema: migrationChoiceQueryOutput,
|
|
234
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
235
|
+
handler: docxQueryMigrationChoices,
|
|
236
|
+
},
|
|
184
237
|
{
|
|
185
238
|
name: 'docx_migrate_template',
|
|
186
239
|
description: 'Migrate a current DOCX into the selected baseline from one complete batch of business choices. Choices reference only opaque ids returned by docx_list_migration_choices; the tool derives all document values, coordinates, plans, and edits.',
|
|
@@ -309,6 +362,62 @@ async function docxListMigrationChoices(args) {
|
|
|
309
362
|
};
|
|
310
363
|
}
|
|
311
364
|
|
|
365
|
+
async function docxQueryMigrationChoices(args) {
|
|
366
|
+
const catalogPath = requireString(args.catalog, 'catalog');
|
|
367
|
+
const bytes = await readFile(catalogPath);
|
|
368
|
+
const catalog = migrationCatalog.parse(JSON.parse(bytes.toString('utf8')));
|
|
369
|
+
const offset = args.offset ?? 0;
|
|
370
|
+
const limit = args.limit ?? 10;
|
|
371
|
+
let source = null;
|
|
372
|
+
let matches;
|
|
373
|
+
|
|
374
|
+
if (args.view === 'sources') {
|
|
375
|
+
matches = catalog.sources;
|
|
376
|
+
} else {
|
|
377
|
+
source = catalog.sources.find(item => item.id === args.sourceChoiceId) ?? null;
|
|
378
|
+
if (!source) {
|
|
379
|
+
throw Object.assign(new Error(`Unknown sourceChoiceId: ${args.sourceChoiceId}`), { code: -32602 });
|
|
380
|
+
}
|
|
381
|
+
const kinds = args.kinds ? new Set(args.kinds) : null;
|
|
382
|
+
const scopes = args.scopes ? new Set(args.scopes) : null;
|
|
383
|
+
const textQuery = args.text?.toLocaleLowerCase();
|
|
384
|
+
matches = catalog.targets.filter(item =>
|
|
385
|
+
(!kinds || kinds.has(item.kind)) &&
|
|
386
|
+
(!scopes || scopes.has(item.scope)) &&
|
|
387
|
+
(!textQuery || migrationChoiceSearchText(item).includes(textQuery)));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const items = matches.slice(offset, offset + limit);
|
|
391
|
+
return {
|
|
392
|
+
tool: 'docx_query_migration_choices',
|
|
393
|
+
catalogSha256: createHash('sha256').update(bytes).digest('hex'),
|
|
394
|
+
view: args.view,
|
|
395
|
+
source,
|
|
396
|
+
items,
|
|
397
|
+
page: {
|
|
398
|
+
offset,
|
|
399
|
+
returned: items.length,
|
|
400
|
+
total: matches.length,
|
|
401
|
+
hasMore: offset + items.length < matches.length,
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function migrationChoiceSearchText(choice) {
|
|
407
|
+
return collectVisibleStrings({ text: choice.text, context: choice.context })
|
|
408
|
+
.join('\n')
|
|
409
|
+
.toLocaleLowerCase();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function collectVisibleStrings(value, fieldName = '') {
|
|
413
|
+
if (typeof value === 'string') return /text/i.test(fieldName) ? [value] : [];
|
|
414
|
+
if (Array.isArray(value)) return value.flatMap(item => collectVisibleStrings(item, fieldName));
|
|
415
|
+
if (value && typeof value === 'object') {
|
|
416
|
+
return Object.entries(value).flatMap(([key, item]) => collectVisibleStrings(item, key));
|
|
417
|
+
}
|
|
418
|
+
return [];
|
|
419
|
+
}
|
|
420
|
+
|
|
312
421
|
async function docxMigrateTemplate(args) {
|
|
313
422
|
return runTemplateMigrationCommand('docx_migrate_template', 'migrate-template', args);
|
|
314
423
|
}
|