gogcli-mcp-slides 2.7.1 → 2.18.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/index.js +20468 -19589
- package/manifest.json +138 -2
- package/package.json +3 -2
- package/server.json +2 -2
- package/src/index.ts +7 -9
- package/src/tools/slides-extra.ts +651 -18
- package/tests/tools/slides-extra.test.ts +541 -23
- package/tsconfig.json +1 -1
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { accountParam, runOrDiagnose } from '../../../gogcli-mcp/src/lib.js';
|
|
3
|
+
import { accountParam, runOrDiagnose, payloadArg } from '../../../gogcli-mcp/src/lib.js';
|
|
4
|
+
import type { GogArg } from '../../../gogcli-mcp/src/lib.js';
|
|
5
|
+
|
|
6
|
+
// Payload routing note — slides differs from gmail/docs.
|
|
7
|
+
//
|
|
8
|
+
// Every `--x` / `--x-file` pair below goes through payloadArg, so a value over
|
|
9
|
+
// PAYLOAD_INLINE_MAX leaves argv and is materialized as a temp file by the
|
|
10
|
+
// executor. What is asymmetric is what gog does when BOTH forms are supplied:
|
|
11
|
+
//
|
|
12
|
+
// gmail drafts/forward and docs cell-update HARD-ERROR ("use only one of
|
|
13
|
+
// --body-html or --body-html-file", "cannot use both --content and
|
|
14
|
+
// --content-file"), so those tools reject the combination before gog runs.
|
|
15
|
+
//
|
|
16
|
+
// slides create-from-markdown / add-slide / update-notes / replace-slide do
|
|
17
|
+
// NOT error (measured on gog 0.34.1). Both flags are accepted and the FILE
|
|
18
|
+
// silently WINS. Callers may already rely on that, so these tools keep it:
|
|
19
|
+
// the caller-supplied *File flag is pushed last and therefore still wins,
|
|
20
|
+
// including over a payloadArg-generated file.
|
|
21
|
+
//
|
|
22
|
+
// Second slides-specific quirk: notes read from a file PRESERVE trailing
|
|
23
|
+
// newlines (a 7-byte file comes back as length 7), unlike gmail bodies, where
|
|
24
|
+
// all trailing newlines are stripped. So notes round-trip byte-for-byte on
|
|
25
|
+
// either side of the threshold.
|
|
4
26
|
|
|
5
27
|
export function registerExtraSlidesTools(server: McpServer): void {
|
|
6
28
|
server.registerTool('gog_slides_create_from_markdown', {
|
|
@@ -14,8 +36,8 @@ export function registerExtraSlidesTools(server: McpServer): void {
|
|
|
14
36
|
account: accountParam,
|
|
15
37
|
},
|
|
16
38
|
}, async ({ title, content, contentFile, parent, debug, account }) => {
|
|
17
|
-
const args = ['slides', 'create-from-markdown', title];
|
|
18
|
-
if (content) args.push(
|
|
39
|
+
const args: GogArg[] = ['slides', 'create-from-markdown', title];
|
|
40
|
+
if (content) args.push(payloadArg('content', 'content-file', content, 'md'));
|
|
19
41
|
if (contentFile) args.push(`--content-file=${contentFile}`);
|
|
20
42
|
if (parent) args.push(`--parent=${parent}`);
|
|
21
43
|
if (debug) args.push('--debug');
|
|
@@ -57,28 +79,32 @@ export function registerExtraSlidesTools(server: McpServer): void {
|
|
|
57
79
|
account: accountParam,
|
|
58
80
|
},
|
|
59
81
|
}, async ({ presentationId, image, notes, notesFile, before, account }) => {
|
|
60
|
-
const args = ['slides', 'add-slide', presentationId, image];
|
|
61
|
-
if (notes) args.push(
|
|
82
|
+
const args: GogArg[] = ['slides', 'add-slide', presentationId, image];
|
|
83
|
+
if (notes) args.push(payloadArg('notes', 'notes-file', notes));
|
|
62
84
|
if (notesFile) args.push(`--notes-file=${notesFile}`);
|
|
63
85
|
if (before) args.push(`--before=${before}`);
|
|
64
86
|
return runOrDiagnose(args, { account });
|
|
65
87
|
});
|
|
66
88
|
|
|
67
89
|
server.registerTool('gog_slides_insert_image', {
|
|
68
|
-
description: 'Place
|
|
90
|
+
description: 'Place an image on an existing slide at a given size and position, from a local file (image) or a public HTTPS URL (url — no Drive upload or sharing required). Unlike gog_slides_add_slide (which creates a new full-bleed image slide), this inserts onto a slide you already have. width is required; omit height to keep aspect ratio when using a local file (gog requires both width and height when using url).',
|
|
69
91
|
inputSchema: {
|
|
70
92
|
presentationId: z.string().describe('Presentation ID'),
|
|
71
93
|
slideId: z.string().describe('Slide ID (object ID of the target slide)'),
|
|
72
|
-
image: z.string().describe('Path to the local image file'),
|
|
94
|
+
image: z.string().optional().describe('Path to the local image file (exactly one of image or url)'),
|
|
95
|
+
url: z.string().optional().describe('Public HTTPS image URL to insert directly — no Drive upload or sharing (exactly one of image or url). gog requires both width and height with url.'),
|
|
73
96
|
width: z.number().describe('Image width, in unit'),
|
|
74
|
-
height: z.number().optional().describe('Image height, in unit; omit to keep the image\'s aspect ratio'),
|
|
97
|
+
height: z.number().optional().describe('Image height, in unit; omit to keep the image\'s aspect ratio (required when using url)'),
|
|
75
98
|
x: z.number().optional().describe('Left position of the image, in unit'),
|
|
76
99
|
y: z.number().optional().describe('Top position of the image, in unit'),
|
|
77
100
|
unit: z.enum(['PT', 'EMU']).optional().describe('Measurement unit for x/y/width/height (default: PT)'),
|
|
78
101
|
account: accountParam,
|
|
79
102
|
},
|
|
80
|
-
}, async ({ presentationId, slideId, image, width, height, x, y, unit, account }) => {
|
|
81
|
-
const args = ['slides', 'insert-image', presentationId, slideId
|
|
103
|
+
}, async ({ presentationId, slideId, image, url, width, height, x, y, unit, account }) => {
|
|
104
|
+
const args = ['slides', 'insert-image', presentationId, slideId];
|
|
105
|
+
if (image) args.push(image);
|
|
106
|
+
args.push(`--width=${width}`);
|
|
107
|
+
if (url) args.push(`--url=${url}`);
|
|
82
108
|
if (height !== undefined) args.push(`--height=${height}`);
|
|
83
109
|
if (x !== undefined) args.push(`--x=${x}`);
|
|
84
110
|
if (y !== undefined) args.push(`--y=${y}`);
|
|
@@ -95,7 +121,8 @@ export function registerExtraSlidesTools(server: McpServer): void {
|
|
|
95
121
|
account: accountParam,
|
|
96
122
|
},
|
|
97
123
|
}, async ({ presentationId, slideId, account }) => {
|
|
98
|
-
|
|
124
|
+
// --force: gog refuses this delete under the runner's --no-input without it.
|
|
125
|
+
return runOrDiagnose(['slides', 'delete-slide', presentationId, slideId, '--force'], { account });
|
|
99
126
|
});
|
|
100
127
|
|
|
101
128
|
server.registerTool('gog_slides_update_notes', {
|
|
@@ -109,27 +136,633 @@ export function registerExtraSlidesTools(server: McpServer): void {
|
|
|
109
136
|
account: accountParam,
|
|
110
137
|
},
|
|
111
138
|
}, async ({ presentationId, slideId, notes, notesFile, account }) => {
|
|
112
|
-
const args = ['slides', 'update-notes', presentationId, slideId];
|
|
113
|
-
if (notes) args.push(
|
|
139
|
+
const args: GogArg[] = ['slides', 'update-notes', presentationId, slideId];
|
|
140
|
+
if (notes) args.push(payloadArg('notes', 'notes-file', notes));
|
|
114
141
|
if (notesFile) args.push(`--notes-file=${notesFile}`);
|
|
115
142
|
return runOrDiagnose(args, { account });
|
|
116
143
|
});
|
|
117
144
|
|
|
118
145
|
server.registerTool('gog_slides_replace_slide', {
|
|
119
|
-
description: 'Replace the image content of an existing slide, with optional speaker notes.',
|
|
146
|
+
description: 'Replace the image content of an existing slide, from a local file (image) or a public HTTPS URL (url — no Drive upload or sharing required), with optional speaker notes.',
|
|
120
147
|
annotations: { destructiveHint: true },
|
|
121
148
|
inputSchema: {
|
|
122
149
|
presentationId: z.string().describe('Presentation ID'),
|
|
123
150
|
slideId: z.string().describe('Slide ID to replace'),
|
|
124
|
-
image: z.string().describe('Path to the new local image file'),
|
|
151
|
+
image: z.string().optional().describe('Path to the new local image file (exactly one of image or url)'),
|
|
152
|
+
url: z.string().optional().describe('Public HTTPS image URL to use directly — no Drive upload or sharing (exactly one of image or url)'),
|
|
125
153
|
notes: z.string().optional().describe('Speaker notes text'),
|
|
126
154
|
notesFile: z.string().optional().describe('Path to a file containing speaker notes'),
|
|
127
155
|
account: accountParam,
|
|
128
156
|
},
|
|
129
|
-
}, async ({ presentationId, slideId, image, notes, notesFile, account }) => {
|
|
130
|
-
const args = ['slides', 'replace-slide', presentationId, slideId
|
|
131
|
-
if (
|
|
157
|
+
}, async ({ presentationId, slideId, image, url, notes, notesFile, account }) => {
|
|
158
|
+
const args: GogArg[] = ['slides', 'replace-slide', presentationId, slideId];
|
|
159
|
+
if (image) args.push(image);
|
|
160
|
+
if (url) args.push(`--url=${url}`);
|
|
161
|
+
if (notes) args.push(payloadArg('notes', 'notes-file', notes));
|
|
132
162
|
if (notesFile) args.push(`--notes-file=${notesFile}`);
|
|
133
163
|
return runOrDiagnose(args, { account });
|
|
134
164
|
});
|
|
165
|
+
|
|
166
|
+
// --- gog 0.29 reads ---
|
|
167
|
+
|
|
168
|
+
server.registerTool('gog_slides_raw', {
|
|
169
|
+
description: 'Dump the raw Google Slides API response (Presentations.Get) as JSON — lossless presentation metadata including every page, element, and style. Use gog_slides_read_slide for a friendlier per-slide view.',
|
|
170
|
+
annotations: { readOnlyHint: true },
|
|
171
|
+
inputSchema: {
|
|
172
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
173
|
+
pretty: z.boolean().optional().describe('Pretty-print the JSON (default: compact single line)'),
|
|
174
|
+
account: accountParam,
|
|
175
|
+
},
|
|
176
|
+
}, async ({ presentationId, pretty, account }) => {
|
|
177
|
+
const args = ['slides', 'raw', presentationId];
|
|
178
|
+
if (pretty) args.push('--pretty');
|
|
179
|
+
return runOrDiagnose(args, { account });
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
server.registerTool('gog_slides_locate', {
|
|
183
|
+
description: 'Locate literal text in a presentation\'s shapes and table cells, returning the containing element object IDs and UTF-16 ranges needed for gog_slides_style_text / gog_slides_link / gog_slides_bullets / gog_slides_insert_text. Read-only.',
|
|
184
|
+
annotations: { readOnlyHint: true },
|
|
185
|
+
inputSchema: {
|
|
186
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
187
|
+
text: z.string().describe('Literal text to locate'),
|
|
188
|
+
page: z.string().optional().describe('Limit matches to one slide object ID'),
|
|
189
|
+
occurrence: z.number().int().optional().describe('Return the Nth occurrence (1-based; default: first)'),
|
|
190
|
+
all: z.boolean().optional().describe('Return all matches instead of just one'),
|
|
191
|
+
matchCase: z.boolean().optional().describe('Case-sensitive matching'),
|
|
192
|
+
failEmpty: z.boolean().optional().describe('Treat no matches as an error instead of returning an empty result'),
|
|
193
|
+
account: accountParam,
|
|
194
|
+
},
|
|
195
|
+
}, async ({ presentationId, text, page, occurrence, all, matchCase, failEmpty, account }) => {
|
|
196
|
+
const args = ['slides', 'locate', presentationId, text];
|
|
197
|
+
if (page) args.push(`--page=${page}`);
|
|
198
|
+
if (occurrence !== undefined) args.push(`--occurrence=${occurrence}`);
|
|
199
|
+
if (all) args.push('--all');
|
|
200
|
+
if (matchCase) args.push('--match-case');
|
|
201
|
+
if (failEmpty) args.push('--fail-empty');
|
|
202
|
+
return runOrDiagnose(args, { account });
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
server.registerTool('gog_slides_thumbnail', {
|
|
206
|
+
description: 'Get or download a rendered thumbnail image for a single slide.',
|
|
207
|
+
annotations: { readOnlyHint: true },
|
|
208
|
+
inputSchema: {
|
|
209
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
210
|
+
slideId: z.string().describe('Slide object ID'),
|
|
211
|
+
format: z.enum(['png', 'jpeg']).optional().describe('Thumbnail image format'),
|
|
212
|
+
size: z.enum(['small', 'medium', 'large']).optional().describe('Thumbnail size'),
|
|
213
|
+
out: z.string().optional().describe('Write the thumbnail image to a local file'),
|
|
214
|
+
overwrite: z.boolean().optional().describe('Overwrite the output file if it already exists'),
|
|
215
|
+
account: accountParam,
|
|
216
|
+
},
|
|
217
|
+
}, async ({ presentationId, slideId, format, size, out, overwrite, account }) => {
|
|
218
|
+
const args = ['slides', 'thumbnail', presentationId, slideId];
|
|
219
|
+
if (format) args.push(`--format=${format}`);
|
|
220
|
+
if (size) args.push(`--size=${size}`);
|
|
221
|
+
if (out) args.push(`--out=${out}`);
|
|
222
|
+
if (overwrite) args.push('--overwrite');
|
|
223
|
+
return runOrDiagnose(args, { account });
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// --- gog 0.29 slide management ---
|
|
227
|
+
|
|
228
|
+
server.registerTool('gog_slides_new_slide', {
|
|
229
|
+
description: 'Create a new native themed slide with a predefined layout (default BLANK) or an exact presentation layout object ID, at a zero-based insertion index.',
|
|
230
|
+
inputSchema: {
|
|
231
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
232
|
+
layout: z.enum(['BIG_NUMBER', 'BLANK', 'CAPTION_ONLY', 'MAIN_POINT', 'ONE_COLUMN_TEXT', 'SECTION_HEADER', 'SECTION_TITLE_AND_DESCRIPTION', 'TITLE', 'TITLE_AND_BODY', 'TITLE_AND_TWO_COLUMNS', 'TITLE_ONLY']).optional().describe('Predefined slide layout (default: BLANK). Mutually exclusive with layoutId.'),
|
|
233
|
+
layoutId: z.string().optional().describe('Exact presentation layout object ID (from gog_slides_info --json). Mutually exclusive with layout.'),
|
|
234
|
+
index: z.number().int().optional().describe('Zero-based insertion index for the new slide'),
|
|
235
|
+
account: accountParam,
|
|
236
|
+
},
|
|
237
|
+
}, async ({ presentationId, layout, layoutId, index, account }) => {
|
|
238
|
+
const args = ['slides', 'new-slide', presentationId];
|
|
239
|
+
if (layout) args.push(`--layout=${layout}`);
|
|
240
|
+
if (layoutId) args.push(`--layout-id=${layoutId}`);
|
|
241
|
+
if (index !== undefined) args.push(`--index=${index}`);
|
|
242
|
+
return runOrDiagnose(args, { account });
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
server.registerTool('gog_slides_duplicate_slide', {
|
|
246
|
+
description: 'Duplicate a slide by object ID, optionally placing the copy at a zero-based insertion index.',
|
|
247
|
+
inputSchema: {
|
|
248
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
249
|
+
slideId: z.string().describe('Slide object ID to duplicate'),
|
|
250
|
+
toIndex: z.number().int().optional().describe('Zero-based insertion index for the duplicated slide'),
|
|
251
|
+
account: accountParam,
|
|
252
|
+
},
|
|
253
|
+
}, async ({ presentationId, slideId, toIndex, account }) => {
|
|
254
|
+
const args = ['slides', 'duplicate-slide', presentationId, slideId];
|
|
255
|
+
if (toIndex !== undefined) args.push(`--to-index=${toIndex}`);
|
|
256
|
+
return runOrDiagnose(args, { account });
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
server.registerTool('gog_slides_move_slide', {
|
|
260
|
+
description: 'Move a slide to a zero-based insertion index within the presentation.',
|
|
261
|
+
inputSchema: {
|
|
262
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
263
|
+
slideId: z.string().describe('Slide object ID to move'),
|
|
264
|
+
toIndex: z.number().int().describe('Zero-based insertion index where the slide should be moved'),
|
|
265
|
+
account: accountParam,
|
|
266
|
+
},
|
|
267
|
+
}, async ({ presentationId, slideId, toIndex, account }) => {
|
|
268
|
+
return runOrDiagnose(['slides', 'move-slide', presentationId, slideId, `--to-index=${toIndex}`], { account });
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// --- gog 0.29 text authoring ---
|
|
272
|
+
|
|
273
|
+
server.registerTool('gog_slides_insert_text', {
|
|
274
|
+
description: 'Insert text into an existing page element (shape or table cell) by object ID. Target a table cell with zero-based row + col. Use replace=true to clear the element\'s existing text first.',
|
|
275
|
+
annotations: { destructiveHint: true },
|
|
276
|
+
inputSchema: {
|
|
277
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
278
|
+
objectId: z.string().describe('Object ID of the target shape or table'),
|
|
279
|
+
text: z.string().describe('Text to insert'),
|
|
280
|
+
row: z.number().int().optional().describe('0-based table row index for cell-targeted text (requires col)'),
|
|
281
|
+
col: z.number().int().optional().describe('0-based table column index for cell-targeted text (requires row)'),
|
|
282
|
+
insertionIndex: z.number().int().optional().describe('Zero-based index where text is inserted within the element\'s existing text'),
|
|
283
|
+
replace: z.boolean().optional().describe('Clear the element\'s existing text before inserting'),
|
|
284
|
+
account: accountParam,
|
|
285
|
+
},
|
|
286
|
+
}, async ({ presentationId, objectId, text, row, col, insertionIndex, replace, account }) => {
|
|
287
|
+
const args = ['slides', 'insert-text', presentationId, objectId, text];
|
|
288
|
+
if (row !== undefined) args.push(`--row=${row}`);
|
|
289
|
+
if (col !== undefined) args.push(`--col=${col}`);
|
|
290
|
+
if (insertionIndex !== undefined) args.push(`--insertion-index=${insertionIndex}`);
|
|
291
|
+
if (replace) args.push('--replace');
|
|
292
|
+
return runOrDiagnose(args, { account });
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
server.registerTool('gog_slides_style_text', {
|
|
296
|
+
description: 'Apply range-scoped text styling to one page element. range is a UTF-16 start:end span (use gog_slides_locate to find it). Boolean flags set the attribute; the no* flags clear it.',
|
|
297
|
+
inputSchema: {
|
|
298
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
299
|
+
objectId: z.string().describe('Object ID of the shape or table cell containing the text'),
|
|
300
|
+
range: z.string().describe('UTF-16 text range as start:end'),
|
|
301
|
+
font: z.string().optional().describe('Font family (e.g. Arial, Georgia)'),
|
|
302
|
+
size: z.number().optional().describe('Font size in points'),
|
|
303
|
+
textColor: z.string().optional().describe('Text color as #RRGGBB or #RGB'),
|
|
304
|
+
bold: z.boolean().optional().describe('Set bold'),
|
|
305
|
+
noBold: z.boolean().optional().describe('Clear bold'),
|
|
306
|
+
italic: z.boolean().optional().describe('Set italic'),
|
|
307
|
+
noItalic: z.boolean().optional().describe('Clear italic'),
|
|
308
|
+
underline: z.boolean().optional().describe('Set underline'),
|
|
309
|
+
noUnderline: z.boolean().optional().describe('Clear underline'),
|
|
310
|
+
account: accountParam,
|
|
311
|
+
},
|
|
312
|
+
}, async ({ presentationId, objectId, range, font, size, textColor, bold, noBold, italic, noItalic, underline, noUnderline, account }) => {
|
|
313
|
+
const args = ['slides', 'style-text', presentationId, objectId, `--range=${range}`];
|
|
314
|
+
if (font) args.push(`--font=${font}`);
|
|
315
|
+
if (size !== undefined) args.push(`--size=${size}`);
|
|
316
|
+
if (textColor) args.push(`--text-color=${textColor}`);
|
|
317
|
+
if (bold) args.push('--bold');
|
|
318
|
+
if (noBold) args.push('--no-bold');
|
|
319
|
+
if (italic) args.push('--italic');
|
|
320
|
+
if (noItalic) args.push('--no-italic');
|
|
321
|
+
if (underline) args.push('--underline');
|
|
322
|
+
if (noUnderline) args.push('--no-underline');
|
|
323
|
+
return runOrDiagnose(args, { account });
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
server.registerTool('gog_slides_link', {
|
|
327
|
+
description: 'Apply or clear a hyperlink on a UTF-16 text range in one page element. Provide url to set the link, or clear=true to remove it.',
|
|
328
|
+
inputSchema: {
|
|
329
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
330
|
+
objectId: z.string().describe('Object ID of the shape or table cell containing the text'),
|
|
331
|
+
range: z.string().describe('UTF-16 text range as start:end'),
|
|
332
|
+
url: z.string().optional().describe('External URL to apply as the hyperlink'),
|
|
333
|
+
clear: z.boolean().optional().describe('Remove the hyperlink from the selected range'),
|
|
334
|
+
account: accountParam,
|
|
335
|
+
},
|
|
336
|
+
}, async ({ presentationId, objectId, range, url, clear, account }) => {
|
|
337
|
+
const args = ['slides', 'link', presentationId, objectId, `--range=${range}`];
|
|
338
|
+
if (url) args.push(`--url=${url}`);
|
|
339
|
+
if (clear) args.push('--clear');
|
|
340
|
+
return runOrDiagnose(args, { account });
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
server.registerTool('gog_slides_bullets', {
|
|
344
|
+
description: 'Turn paragraph bullets on or off for a UTF-16 paragraph range in one page element. Use on (optionally with a preset glyph) or off.',
|
|
345
|
+
inputSchema: {
|
|
346
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
347
|
+
objectId: z.string().describe('Object ID of the shape or table cell containing the paragraphs'),
|
|
348
|
+
range: z.string().describe('UTF-16 paragraph range as start:end'),
|
|
349
|
+
on: z.boolean().optional().describe('Turn bullets on for the selected paragraphs'),
|
|
350
|
+
off: z.boolean().optional().describe('Turn bullets off for the selected paragraphs'),
|
|
351
|
+
preset: z.string().optional().describe('Slides bullet glyph preset to use with on (e.g. BULLET_DISC_CIRCLE_SQUARE)'),
|
|
352
|
+
account: accountParam,
|
|
353
|
+
},
|
|
354
|
+
}, async ({ presentationId, objectId, range, on, off, preset, account }) => {
|
|
355
|
+
const args = ['slides', 'bullets', presentationId, objectId, `--range=${range}`];
|
|
356
|
+
if (on) args.push('--on');
|
|
357
|
+
if (off) args.push('--off');
|
|
358
|
+
if (preset) args.push(`--preset=${preset}`);
|
|
359
|
+
return runOrDiagnose(args, { account });
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
server.registerTool('gog_slides_replace_text', {
|
|
363
|
+
description: 'Find-and-replace text within an explicit scope. You MUST choose a scope — restrict to a single shape (object), one or more slides (pages), or the entire presentation (all=true). There is no whole-deck default; gog rejects the call if no scope is given.',
|
|
364
|
+
annotations: { destructiveHint: true },
|
|
365
|
+
inputSchema: {
|
|
366
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
367
|
+
find: z.string().describe('Text to find'),
|
|
368
|
+
replacement: z.string().describe('Replacement text'),
|
|
369
|
+
object: z.string().optional().describe('Scope: restrict replacement to a single shape text object ID'),
|
|
370
|
+
pages: z.array(z.string()).optional().describe('Scope: restrict replacement to these slide object IDs (repeatable)'),
|
|
371
|
+
all: z.boolean().optional().describe('Scope: replace matching text across the entire presentation'),
|
|
372
|
+
matchCase: z.boolean().optional().describe('Case-sensitive match (default: false)'),
|
|
373
|
+
account: accountParam,
|
|
374
|
+
},
|
|
375
|
+
}, async ({ presentationId, find, replacement, object, pages, all, matchCase, account }) => {
|
|
376
|
+
const args = ['slides', 'replace-text', presentationId, find, replacement];
|
|
377
|
+
if (object) args.push(`--object=${object}`);
|
|
378
|
+
if (pages) for (const p of pages) args.push(`--page=${p}`);
|
|
379
|
+
if (all) args.push('--all');
|
|
380
|
+
if (matchCase) args.push('--match-case');
|
|
381
|
+
return runOrDiagnose(args, { account });
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// --- gog 0.29 native shapes & lines (element subtree) ---
|
|
385
|
+
|
|
386
|
+
server.registerTool('gog_slides_element_create_shape', {
|
|
387
|
+
description: 'Create a native shape on a slide. type is a Slides shape type (e.g. RECTANGLE, TEXT_BOX, ELLIPSE, ROUND_RECTANGLE). Position/size are in unit (default PT).',
|
|
388
|
+
inputSchema: {
|
|
389
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
390
|
+
slideId: z.string().describe('Slide object ID to create the shape on'),
|
|
391
|
+
type: z.string().optional().describe('Slides shape type (e.g. RECTANGLE, TEXT_BOX, ELLIPSE)'),
|
|
392
|
+
x: z.number().optional().describe('Left position'),
|
|
393
|
+
y: z.number().optional().describe('Top position'),
|
|
394
|
+
width: z.number().optional().describe('Shape width'),
|
|
395
|
+
height: z.number().optional().describe('Shape height'),
|
|
396
|
+
unit: z.enum(['PT', 'EMU']).optional().describe('Geometry unit (default: PT)'),
|
|
397
|
+
objectId: z.string().optional().describe('Optional stable object ID (5-50 chars: letters, digits, _, -, :)'),
|
|
398
|
+
account: accountParam,
|
|
399
|
+
},
|
|
400
|
+
}, async ({ presentationId, slideId, type, x, y, width, height, unit, objectId, account }) => {
|
|
401
|
+
const args = ['slides', 'element', 'create-shape', presentationId, slideId];
|
|
402
|
+
if (type) args.push(`--type=${type}`);
|
|
403
|
+
if (x !== undefined) args.push(`--x=${x}`);
|
|
404
|
+
if (y !== undefined) args.push(`--y=${y}`);
|
|
405
|
+
if (width !== undefined) args.push(`--width=${width}`);
|
|
406
|
+
if (height !== undefined) args.push(`--height=${height}`);
|
|
407
|
+
if (unit) args.push(`--unit=${unit}`);
|
|
408
|
+
if (objectId) args.push(`--object-id=${objectId}`);
|
|
409
|
+
return runOrDiagnose(args, { account });
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
server.registerTool('gog_slides_element_create_line', {
|
|
413
|
+
description: 'Create a native line on a slide. category is the connector routing (STRAIGHT, BENT, CURVED). Start position and extent are in unit (default PT).',
|
|
414
|
+
inputSchema: {
|
|
415
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
416
|
+
slideId: z.string().describe('Slide object ID to create the line on'),
|
|
417
|
+
category: z.enum(['STRAIGHT', 'BENT', 'CURVED']).optional().describe('Line category / routing (default: STRAIGHT)'),
|
|
418
|
+
x: z.number().optional().describe('Start X position'),
|
|
419
|
+
y: z.number().optional().describe('Start Y position'),
|
|
420
|
+
width: z.number().optional().describe('Horizontal extent'),
|
|
421
|
+
height: z.number().optional().describe('Vertical extent'),
|
|
422
|
+
unit: z.enum(['PT', 'EMU']).optional().describe('Geometry unit (default: PT)'),
|
|
423
|
+
objectId: z.string().optional().describe('Optional stable object ID (5-50 chars: letters, digits, _, -, :)'),
|
|
424
|
+
account: accountParam,
|
|
425
|
+
},
|
|
426
|
+
}, async ({ presentationId, slideId, category, x, y, width, height, unit, objectId, account }) => {
|
|
427
|
+
const args = ['slides', 'element', 'create-line', presentationId, slideId];
|
|
428
|
+
if (category) args.push(`--category=${category}`);
|
|
429
|
+
if (x !== undefined) args.push(`--x=${x}`);
|
|
430
|
+
if (y !== undefined) args.push(`--y=${y}`);
|
|
431
|
+
if (width !== undefined) args.push(`--width=${width}`);
|
|
432
|
+
if (height !== undefined) args.push(`--height=${height}`);
|
|
433
|
+
if (unit) args.push(`--unit=${unit}`);
|
|
434
|
+
if (objectId) args.push(`--object-id=${objectId}`);
|
|
435
|
+
return runOrDiagnose(args, { account });
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
server.registerTool('gog_slides_element_style', {
|
|
439
|
+
description: 'Style a shape fill/outline or a line. Set kind to shape or line. Colors are #RGB or #RRGGBB.',
|
|
440
|
+
inputSchema: {
|
|
441
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
442
|
+
objectId: z.string().describe('Object ID of the shape or line'),
|
|
443
|
+
kind: z.enum(['shape', 'line']).optional().describe('Element kind (default: shape)'),
|
|
444
|
+
fillColor: z.string().optional().describe('Shape fill as #RGB or #RRGGBB'),
|
|
445
|
+
fillTransparent: z.boolean().optional().describe('Remove the shape fill'),
|
|
446
|
+
outlineColor: z.string().optional().describe('Shape outline or line color as #RGB or #RRGGBB'),
|
|
447
|
+
outlineWeight: z.number().optional().describe('Shape outline or line weight in points'),
|
|
448
|
+
outlineDash: z.enum(['SOLID', 'DOT', 'DASH', 'DASH_DOT', 'LONG_DASH', 'LONG_DASH_DOT']).optional().describe('Shape outline or line dash style'),
|
|
449
|
+
outlineTransparent: z.boolean().optional().describe('Remove the shape outline or make the line transparent'),
|
|
450
|
+
account: accountParam,
|
|
451
|
+
},
|
|
452
|
+
}, async ({ presentationId, objectId, kind, fillColor, fillTransparent, outlineColor, outlineWeight, outlineDash, outlineTransparent, account }) => {
|
|
453
|
+
const args = ['slides', 'element', 'style', presentationId, objectId];
|
|
454
|
+
if (kind) args.push(`--kind=${kind}`);
|
|
455
|
+
if (fillColor) args.push(`--fill-color=${fillColor}`);
|
|
456
|
+
if (fillTransparent) args.push('--fill-transparent');
|
|
457
|
+
if (outlineColor) args.push(`--outline-color=${outlineColor}`);
|
|
458
|
+
if (outlineWeight !== undefined) args.push(`--outline-weight=${outlineWeight}`);
|
|
459
|
+
if (outlineDash) args.push(`--outline-dash=${outlineDash}`);
|
|
460
|
+
if (outlineTransparent) args.push('--outline-transparent');
|
|
461
|
+
return runOrDiagnose(args, { account });
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
server.registerTool('gog_slides_element_transform', {
|
|
465
|
+
description: 'Move, resize, rotate, or shear a page element. apply-mode RELATIVE (default) composes with the existing transform; ABSOLUTE replaces it. Translation is in unit (default PT).',
|
|
466
|
+
inputSchema: {
|
|
467
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
468
|
+
objectId: z.string().describe('Object ID of the element to transform'),
|
|
469
|
+
translateX: z.number().optional().describe('X translation'),
|
|
470
|
+
translateY: z.number().optional().describe('Y translation'),
|
|
471
|
+
scaleX: z.number().optional().describe('X scale (omitted axis defaults to 1)'),
|
|
472
|
+
scaleY: z.number().optional().describe('Y scale (omitted axis defaults to 1)'),
|
|
473
|
+
shearX: z.number().optional().describe('X shear'),
|
|
474
|
+
shearY: z.number().optional().describe('Y shear'),
|
|
475
|
+
rotate: z.number().optional().describe('Clockwise rotation in degrees around the element origin'),
|
|
476
|
+
applyMode: z.enum(['RELATIVE', 'ABSOLUTE']).optional().describe('Compose with (RELATIVE, default) or replace (ABSOLUTE) the existing transform'),
|
|
477
|
+
unit: z.enum(['PT', 'EMU']).optional().describe('Translation unit (default: PT)'),
|
|
478
|
+
account: accountParam,
|
|
479
|
+
},
|
|
480
|
+
}, async ({ presentationId, objectId, translateX, translateY, scaleX, scaleY, shearX, shearY, rotate, applyMode, unit, account }) => {
|
|
481
|
+
const args = ['slides', 'element', 'transform', presentationId, objectId];
|
|
482
|
+
if (translateX !== undefined) args.push(`--translate-x=${translateX}`);
|
|
483
|
+
if (translateY !== undefined) args.push(`--translate-y=${translateY}`);
|
|
484
|
+
if (scaleX !== undefined) args.push(`--scale-x=${scaleX}`);
|
|
485
|
+
if (scaleY !== undefined) args.push(`--scale-y=${scaleY}`);
|
|
486
|
+
if (shearX !== undefined) args.push(`--shear-x=${shearX}`);
|
|
487
|
+
if (shearY !== undefined) args.push(`--shear-y=${shearY}`);
|
|
488
|
+
if (rotate !== undefined) args.push(`--rotate=${rotate}`);
|
|
489
|
+
if (applyMode) args.push(`--apply-mode=${applyMode}`);
|
|
490
|
+
if (unit) args.push(`--unit=${unit}`);
|
|
491
|
+
return runOrDiagnose(args, { account });
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
server.registerTool('gog_slides_element_z_order', {
|
|
495
|
+
description: 'Change a page element\'s stacking order.',
|
|
496
|
+
inputSchema: {
|
|
497
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
498
|
+
objectId: z.string().describe('Object ID of the element to restack'),
|
|
499
|
+
operation: z.enum(['BRING_FORWARD', 'BRING_TO_FRONT', 'SEND_BACKWARD', 'SEND_TO_BACK']).describe('Stacking operation'),
|
|
500
|
+
account: accountParam,
|
|
501
|
+
},
|
|
502
|
+
}, async ({ presentationId, objectId, operation, account }) => {
|
|
503
|
+
return runOrDiagnose(['slides', 'element', 'z-order', presentationId, objectId, `--operation=${operation}`], { account });
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
server.registerTool('gog_slides_element_group', {
|
|
507
|
+
description: 'Group two or more page elements into a single group.',
|
|
508
|
+
inputSchema: {
|
|
509
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
510
|
+
objectIds: z.array(z.string()).min(2).describe('Two or more element object IDs to group'),
|
|
511
|
+
groupId: z.string().optional().describe('Optional stable group object ID'),
|
|
512
|
+
account: accountParam,
|
|
513
|
+
},
|
|
514
|
+
}, async ({ presentationId, objectIds, groupId, account }) => {
|
|
515
|
+
const args = ['slides', 'element', 'group', presentationId, ...objectIds];
|
|
516
|
+
if (groupId) args.push(`--group-id=${groupId}`);
|
|
517
|
+
return runOrDiagnose(args, { account });
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
server.registerTool('gog_slides_element_ungroup', {
|
|
521
|
+
description: 'Ungroup one or more element groups back into their constituent elements.',
|
|
522
|
+
inputSchema: {
|
|
523
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
524
|
+
groupIds: z.array(z.string()).min(1).describe('One or more group object IDs to ungroup'),
|
|
525
|
+
account: accountParam,
|
|
526
|
+
},
|
|
527
|
+
}, async ({ presentationId, groupIds, account }) => {
|
|
528
|
+
return runOrDiagnose(['slides', 'element', 'ungroup', presentationId, ...groupIds], { account });
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
server.registerTool('gog_slides_element_alt_text', {
|
|
532
|
+
description: 'Set or clear a page element\'s accessibility title and/or description. Pass an empty string to clear a field.',
|
|
533
|
+
inputSchema: {
|
|
534
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
535
|
+
objectId: z.string().describe('Object ID of the element'),
|
|
536
|
+
title: z.string().optional().describe('Accessibility title (empty string clears it)'),
|
|
537
|
+
description: z.string().optional().describe('Accessibility description (empty string clears it)'),
|
|
538
|
+
account: accountParam,
|
|
539
|
+
},
|
|
540
|
+
}, async ({ presentationId, objectId, title, description, account }) => {
|
|
541
|
+
const args = ['slides', 'element', 'alt-text', presentationId, objectId];
|
|
542
|
+
if (title !== undefined) args.push(`--title=${title}`);
|
|
543
|
+
if (description !== undefined) args.push(`--description=${description}`);
|
|
544
|
+
return runOrDiagnose(args, { account });
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
server.registerTool('gog_slides_element_delete', {
|
|
548
|
+
description: 'Delete one page element by object ID.',
|
|
549
|
+
annotations: { destructiveHint: true },
|
|
550
|
+
inputSchema: {
|
|
551
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
552
|
+
objectId: z.string().describe('Object ID of the element to delete'),
|
|
553
|
+
account: accountParam,
|
|
554
|
+
},
|
|
555
|
+
}, async ({ presentationId, objectId, account }) => {
|
|
556
|
+
// --force: gog refuses this delete under the runner's --no-input without it.
|
|
557
|
+
return runOrDiagnose(['slides', 'element', 'delete', presentationId, objectId, '--force'], { account });
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// --- gog 0.29 native tables (table subtree). Cell addressing is zero-based. ---
|
|
561
|
+
|
|
562
|
+
server.registerTool('gog_slides_table_create', {
|
|
563
|
+
description: 'Create an auto-sized native table on a slide with the given row and column counts.',
|
|
564
|
+
inputSchema: {
|
|
565
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
566
|
+
slideId: z.string().describe('Slide object ID to create the table on'),
|
|
567
|
+
rows: z.number().int().min(1).describe('Number of rows (>=1)'),
|
|
568
|
+
cols: z.number().int().min(1).describe('Number of columns (>=1)'),
|
|
569
|
+
objectId: z.string().optional().describe('Optional stable table object ID (5-50 chars: letters, digits, _, -, :)'),
|
|
570
|
+
account: accountParam,
|
|
571
|
+
},
|
|
572
|
+
}, async ({ presentationId, slideId, rows, cols, objectId, account }) => {
|
|
573
|
+
const args = ['slides', 'table', 'create', presentationId, slideId, `--rows=${rows}`, `--cols=${cols}`];
|
|
574
|
+
if (objectId) args.push(`--object-id=${objectId}`);
|
|
575
|
+
return runOrDiagnose(args, { account });
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
server.registerTool('gog_slides_table_cell_style', {
|
|
579
|
+
description: 'Style one zero-based table cell: background fill, vertical content alignment, and inline text styling (optionally scoped to a UTF-16 range within the cell). Boolean flags set the attribute; the no* flags clear it.',
|
|
580
|
+
inputSchema: {
|
|
581
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
582
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
583
|
+
row: z.number().int().describe('0-based table row index'),
|
|
584
|
+
col: z.number().int().describe('0-based table column index'),
|
|
585
|
+
range: z.string().optional().describe('UTF-16 text range as start:end to scope text styling within the cell'),
|
|
586
|
+
fillColor: z.string().optional().describe('Cell background fill as #RGB or #RRGGBB'),
|
|
587
|
+
fillTransparent: z.boolean().optional().describe('Remove the cell background fill'),
|
|
588
|
+
contentAlign: z.enum(['TOP', 'MIDDLE', 'BOTTOM']).optional().describe('Vertical content alignment within the cell'),
|
|
589
|
+
font: z.string().optional().describe('Font family (e.g. Arial, Georgia)'),
|
|
590
|
+
size: z.number().optional().describe('Font size in points'),
|
|
591
|
+
textColor: z.string().optional().describe('Text color as #RRGGBB or #RGB'),
|
|
592
|
+
bold: z.boolean().optional().describe('Set bold'),
|
|
593
|
+
noBold: z.boolean().optional().describe('Clear bold'),
|
|
594
|
+
italic: z.boolean().optional().describe('Set italic'),
|
|
595
|
+
noItalic: z.boolean().optional().describe('Clear italic'),
|
|
596
|
+
underline: z.boolean().optional().describe('Set underline'),
|
|
597
|
+
noUnderline: z.boolean().optional().describe('Clear underline'),
|
|
598
|
+
account: accountParam,
|
|
599
|
+
},
|
|
600
|
+
}, async ({ presentationId, tableObjectId, row, col, range, fillColor, fillTransparent, contentAlign, font, size, textColor, bold, noBold, italic, noItalic, underline, noUnderline, account }) => {
|
|
601
|
+
const args = ['slides', 'table', 'cell', 'style', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
|
|
602
|
+
if (range) args.push(`--range=${range}`);
|
|
603
|
+
if (fillColor) args.push(`--fill-color=${fillColor}`);
|
|
604
|
+
if (fillTransparent) args.push('--fill-transparent');
|
|
605
|
+
if (contentAlign) args.push(`--content-align=${contentAlign}`);
|
|
606
|
+
if (font) args.push(`--font=${font}`);
|
|
607
|
+
if (size !== undefined) args.push(`--size=${size}`);
|
|
608
|
+
if (textColor) args.push(`--text-color=${textColor}`);
|
|
609
|
+
if (bold) args.push('--bold');
|
|
610
|
+
if (noBold) args.push('--no-bold');
|
|
611
|
+
if (italic) args.push('--italic');
|
|
612
|
+
if (noItalic) args.push('--no-italic');
|
|
613
|
+
if (underline) args.push('--underline');
|
|
614
|
+
if (noUnderline) args.push('--no-underline');
|
|
615
|
+
return runOrDiagnose(args, { account });
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
server.registerTool('gog_slides_table_border_style', {
|
|
619
|
+
description: 'Style borders around or within a zero-based table cell range. position selects which borders are affected; dash sets the line style.',
|
|
620
|
+
inputSchema: {
|
|
621
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
622
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
623
|
+
row: z.number().int().describe('0-based starting row index'),
|
|
624
|
+
col: z.number().int().describe('0-based starting column index'),
|
|
625
|
+
rowSpan: z.number().int().optional().describe('Number of rows in the range'),
|
|
626
|
+
colSpan: z.number().int().optional().describe('Number of columns in the range'),
|
|
627
|
+
position: z.enum(['ALL', 'OUTER', 'INNER', 'INNER_HORIZONTAL', 'INNER_VERTICAL', 'TOP', 'BOTTOM', 'LEFT', 'RIGHT']).optional().describe('Which borders to style'),
|
|
628
|
+
borderColor: z.string().optional().describe('Border color as #RGB or #RRGGBB'),
|
|
629
|
+
weight: z.number().optional().describe('Border weight in points'),
|
|
630
|
+
dash: z.enum(['SOLID', 'DOT', 'DASH', 'DASH_DOT', 'LONG_DASH', 'LONG_DASH_DOT']).optional().describe('Border dash style'),
|
|
631
|
+
transparent: z.boolean().optional().describe('Make the selected borders transparent'),
|
|
632
|
+
account: accountParam,
|
|
633
|
+
},
|
|
634
|
+
}, async ({ presentationId, tableObjectId, row, col, rowSpan, colSpan, position, borderColor, weight, dash, transparent, account }) => {
|
|
635
|
+
const args = ['slides', 'table', 'border', 'style', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
|
|
636
|
+
if (rowSpan !== undefined) args.push(`--row-span=${rowSpan}`);
|
|
637
|
+
if (colSpan !== undefined) args.push(`--col-span=${colSpan}`);
|
|
638
|
+
if (position) args.push(`--position=${position}`);
|
|
639
|
+
if (borderColor) args.push(`--border-color=${borderColor}`);
|
|
640
|
+
if (weight !== undefined) args.push(`--weight=${weight}`);
|
|
641
|
+
if (dash) args.push(`--dash=${dash}`);
|
|
642
|
+
if (transparent) args.push('--transparent');
|
|
643
|
+
return runOrDiagnose(args, { account });
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
server.registerTool('gog_slides_table_column_insert', {
|
|
647
|
+
description: 'Insert one or more columns relative to a zero-based table column. Inserts to the left by default, or to the right with right=true.',
|
|
648
|
+
inputSchema: {
|
|
649
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
650
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
651
|
+
col: z.number().int().describe('0-based reference column index'),
|
|
652
|
+
count: z.number().int().optional().describe('Number of columns to insert (default: 1)'),
|
|
653
|
+
right: z.boolean().optional().describe('Insert to the right of the reference column instead of the left'),
|
|
654
|
+
account: accountParam,
|
|
655
|
+
},
|
|
656
|
+
}, async ({ presentationId, tableObjectId, col, count, right, account }) => {
|
|
657
|
+
const args = ['slides', 'table', 'column', 'insert', presentationId, tableObjectId, `--col=${col}`];
|
|
658
|
+
if (count !== undefined) args.push(`--count=${count}`);
|
|
659
|
+
if (right) args.push('--right');
|
|
660
|
+
return runOrDiagnose(args, { account });
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
server.registerTool('gog_slides_table_column_delete', {
|
|
664
|
+
description: 'Delete the column containing a zero-based table cell.',
|
|
665
|
+
annotations: { destructiveHint: true },
|
|
666
|
+
inputSchema: {
|
|
667
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
668
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
669
|
+
col: z.number().int().describe('0-based column index to delete'),
|
|
670
|
+
account: accountParam,
|
|
671
|
+
},
|
|
672
|
+
}, async ({ presentationId, tableObjectId, col, account }) => {
|
|
673
|
+
return runOrDiagnose(['slides', 'table', 'column', 'delete', presentationId, tableObjectId, `--col=${col}`, '--force'], { account });
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
server.registerTool('gog_slides_table_column_size', {
|
|
677
|
+
description: 'Set the width of a zero-based table column.',
|
|
678
|
+
inputSchema: {
|
|
679
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
680
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
681
|
+
col: z.number().int().describe('0-based column index'),
|
|
682
|
+
width: z.number().describe('Column width in points'),
|
|
683
|
+
account: accountParam,
|
|
684
|
+
},
|
|
685
|
+
}, async ({ presentationId, tableObjectId, col, width, account }) => {
|
|
686
|
+
return runOrDiagnose(['slides', 'table', 'column', 'size', presentationId, tableObjectId, `--col=${col}`, `--width=${width}`], { account });
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
server.registerTool('gog_slides_table_row_insert', {
|
|
690
|
+
description: 'Insert one or more rows relative to a zero-based table row. Inserts above by default, or below with below=true.',
|
|
691
|
+
inputSchema: {
|
|
692
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
693
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
694
|
+
row: z.number().int().describe('0-based reference row index'),
|
|
695
|
+
count: z.number().int().optional().describe('Number of rows to insert (default: 1)'),
|
|
696
|
+
below: z.boolean().optional().describe('Insert below the reference row instead of above'),
|
|
697
|
+
account: accountParam,
|
|
698
|
+
},
|
|
699
|
+
}, async ({ presentationId, tableObjectId, row, count, below, account }) => {
|
|
700
|
+
const args = ['slides', 'table', 'row', 'insert', presentationId, tableObjectId, `--row=${row}`];
|
|
701
|
+
if (count !== undefined) args.push(`--count=${count}`);
|
|
702
|
+
if (below) args.push('--below');
|
|
703
|
+
return runOrDiagnose(args, { account });
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
server.registerTool('gog_slides_table_row_delete', {
|
|
707
|
+
description: 'Delete the row containing a zero-based table cell.',
|
|
708
|
+
annotations: { destructiveHint: true },
|
|
709
|
+
inputSchema: {
|
|
710
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
711
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
712
|
+
row: z.number().int().describe('0-based row index to delete'),
|
|
713
|
+
account: accountParam,
|
|
714
|
+
},
|
|
715
|
+
}, async ({ presentationId, tableObjectId, row, account }) => {
|
|
716
|
+
return runOrDiagnose(['slides', 'table', 'row', 'delete', presentationId, tableObjectId, `--row=${row}`, '--force'], { account });
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
server.registerTool('gog_slides_table_row_size', {
|
|
720
|
+
description: 'Set the minimum height of a zero-based table row.',
|
|
721
|
+
inputSchema: {
|
|
722
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
723
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
724
|
+
row: z.number().int().describe('0-based row index'),
|
|
725
|
+
height: z.number().describe('Minimum row height in points'),
|
|
726
|
+
account: accountParam,
|
|
727
|
+
},
|
|
728
|
+
}, async ({ presentationId, tableObjectId, row, height, account }) => {
|
|
729
|
+
return runOrDiagnose(['slides', 'table', 'row', 'size', presentationId, tableObjectId, `--row=${row}`, `--height=${height}`], { account });
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
server.registerTool('gog_slides_table_merge', {
|
|
733
|
+
description: 'Merge a rectangular table cell range starting at a zero-based cell. Content of non-anchor cells is absorbed by the merge; use gog_slides_table_unmerge to split back.',
|
|
734
|
+
annotations: { destructiveHint: true },
|
|
735
|
+
inputSchema: {
|
|
736
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
737
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
738
|
+
row: z.number().int().describe('0-based anchor row index'),
|
|
739
|
+
col: z.number().int().describe('0-based anchor column index'),
|
|
740
|
+
rowSpan: z.number().int().optional().describe('Number of rows to merge'),
|
|
741
|
+
colSpan: z.number().int().optional().describe('Number of columns to merge'),
|
|
742
|
+
account: accountParam,
|
|
743
|
+
},
|
|
744
|
+
}, async ({ presentationId, tableObjectId, row, col, rowSpan, colSpan, account }) => {
|
|
745
|
+
const args = ['slides', 'table', 'merge', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
|
|
746
|
+
if (rowSpan !== undefined) args.push(`--row-span=${rowSpan}`);
|
|
747
|
+
if (colSpan !== undefined) args.push(`--col-span=${colSpan}`);
|
|
748
|
+
return runOrDiagnose(args, { account });
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
server.registerTool('gog_slides_table_unmerge', {
|
|
752
|
+
description: 'Unmerge (split) a rectangular range of previously merged cells, starting at a zero-based cell.',
|
|
753
|
+
inputSchema: {
|
|
754
|
+
presentationId: z.string().describe('Presentation ID'),
|
|
755
|
+
tableObjectId: z.string().describe('Table object ID'),
|
|
756
|
+
row: z.number().int().describe('0-based anchor row index'),
|
|
757
|
+
col: z.number().int().describe('0-based anchor column index'),
|
|
758
|
+
rowSpan: z.number().int().optional().describe('Number of rows in the range'),
|
|
759
|
+
colSpan: z.number().int().optional().describe('Number of columns in the range'),
|
|
760
|
+
account: accountParam,
|
|
761
|
+
},
|
|
762
|
+
}, async ({ presentationId, tableObjectId, row, col, rowSpan, colSpan, account }) => {
|
|
763
|
+
const args = ['slides', 'table', 'unmerge', presentationId, tableObjectId, `--row=${row}`, `--col=${col}`];
|
|
764
|
+
if (rowSpan !== undefined) args.push(`--row-span=${rowSpan}`);
|
|
765
|
+
if (colSpan !== undefined) args.push(`--col-span=${colSpan}`);
|
|
766
|
+
return runOrDiagnose(args, { account });
|
|
767
|
+
});
|
|
135
768
|
}
|