gogcli-mcp-slides 2.0.4 → 2.0.7

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.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
10
- "version": "2.0.4"
10
+ "version": "2.0.7"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "gogcli (Slides)",
16
16
  "source": "./",
17
17
  "description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
18
- "version": "2.0.4",
18
+ "version": "2.0.7",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gogcli-mcp-slides",
3
3
  "displayName": "gogcli (Slides)",
4
- "version": "2.0.4",
4
+ "version": "2.0.7",
5
5
  "description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/dist/index.js CHANGED
@@ -30864,6 +30864,11 @@ var EMPTY_COMPLETION_RESULT = {
30864
30864
  // ../gogcli-mcp/src/runner.ts
30865
30865
  import { spawn } from "node:child_process";
30866
30866
  var TIMEOUT_MS = 3e4;
30867
+ function envOrUndefined(key) {
30868
+ const value = process.env[key];
30869
+ if (!value || value.startsWith("${")) return void 0;
30870
+ return value;
30871
+ }
30867
30872
  function formatTimeout(ms) {
30868
30873
  const seconds = Math.round(ms / 1e3);
30869
30874
  if (seconds >= 60) {
@@ -30874,7 +30879,7 @@ function formatTimeout(ms) {
30874
30879
  }
30875
30880
  async function run(args, options = {}) {
30876
30881
  const { account, spawner = spawn, interactive = false, timeout } = options;
30877
- const effectiveAccount = account ?? process.env.GOG_ACCOUNT;
30882
+ const effectiveAccount = account ?? envOrUndefined("GOG_ACCOUNT");
30878
30883
  const fullArgs = ["--json", "--color=never"];
30879
30884
  if (!interactive) {
30880
30885
  fullArgs.push("--no-input");
@@ -30886,7 +30891,7 @@ async function run(args, options = {}) {
30886
30891
  const effectiveTimeout = timeout ?? TIMEOUT_MS;
30887
30892
  return new Promise((resolve, reject) => {
30888
30893
  const { GOG_ACCESS_TOKEN: _, ...cleanEnv } = process.env;
30889
- const child = spawner(process.env.GOG_PATH ?? "gog", fullArgs, { env: cleanEnv });
30894
+ const child = spawner(envOrUndefined("GOG_PATH") ?? "gog", fullArgs, { env: cleanEnv });
30890
30895
  const stdoutChunks = [];
30891
30896
  const stderrChunks = [];
30892
30897
  let settled = false;
@@ -31068,6 +31073,64 @@ function registerSlidesTools(server2) {
31068
31073
  if (template) args.push(`--template=${template}`);
31069
31074
  return runOrDiagnose(args, { account });
31070
31075
  });
31076
+ server2.registerTool("gog_slides_copy", {
31077
+ description: "Copy a Google Slides presentation to a new presentation with the given title.",
31078
+ inputSchema: {
31079
+ presentationId: external_exports.string().describe("Presentation ID to copy"),
31080
+ title: external_exports.string().describe("Title for the new copy"),
31081
+ parent: external_exports.string().optional().describe("Destination folder ID"),
31082
+ account: accountParam
31083
+ }
31084
+ }, async ({ presentationId, title, parent, account }) => {
31085
+ const args = ["slides", "copy", presentationId, title];
31086
+ if (parent) args.push(`--parent=${parent}`);
31087
+ return runOrDiagnose(args, { account });
31088
+ });
31089
+ server2.registerTool("gog_slides_list_slides", {
31090
+ description: "List slides in a Google Slides presentation.",
31091
+ annotations: { readOnlyHint: true },
31092
+ inputSchema: {
31093
+ presentationId: external_exports.string().describe("Presentation ID"),
31094
+ account: accountParam
31095
+ }
31096
+ }, async ({ presentationId, account }) => {
31097
+ return runOrDiagnose(["slides", "list-slides", presentationId], { account });
31098
+ });
31099
+ server2.registerTool("gog_slides_read_slide", {
31100
+ description: "Read the content of a slide (text, shapes, speaker notes).",
31101
+ annotations: { readOnlyHint: true },
31102
+ inputSchema: {
31103
+ presentationId: external_exports.string().describe("Presentation ID"),
31104
+ slideId: external_exports.string().describe("Slide ID to read"),
31105
+ account: accountParam
31106
+ }
31107
+ }, async ({ presentationId, slideId, account }) => {
31108
+ return runOrDiagnose(["slides", "read-slide", presentationId, slideId], { account });
31109
+ });
31110
+ server2.registerTool("gog_slides_run", {
31111
+ description: "Run any gog slides subcommand not covered by the other tools. Run `gog slides --help` for the full list of subcommands, or `gog slides <subcommand> --help` for flags on a specific subcommand.",
31112
+ annotations: { destructiveHint: true },
31113
+ inputSchema: {
31114
+ subcommand: external_exports.string().describe("The gog slides subcommand to run"),
31115
+ args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31116
+ account: accountParam
31117
+ }
31118
+ }, async ({ subcommand, args, account }) => {
31119
+ return runOrDiagnose(["slides", subcommand, ...args], { account });
31120
+ });
31121
+ }
31122
+
31123
+ // ../gogcli-mcp/src/server.ts
31124
+ var VERSION = true ? "2.0.7" : "0.0.0";
31125
+ function createServer(options) {
31126
+ return new McpServer({
31127
+ name: options?.name ?? "gogcli",
31128
+ version: options?.version ?? VERSION
31129
+ });
31130
+ }
31131
+
31132
+ // src/tools/slides-extra.ts
31133
+ function registerExtraSlidesTools(server2) {
31071
31134
  server2.registerTool("gog_slides_create_from_markdown", {
31072
31135
  description: "Create a new Google Slides presentation from markdown content (inline or from a file).",
31073
31136
  inputSchema: {
@@ -31109,19 +31172,6 @@ function registerSlidesTools(server2) {
31109
31172
  if (exact) args.push("--exact");
31110
31173
  return runOrDiagnose(args, { account });
31111
31174
  });
31112
- server2.registerTool("gog_slides_copy", {
31113
- description: "Copy a Google Slides presentation to a new presentation with the given title.",
31114
- inputSchema: {
31115
- presentationId: external_exports.string().describe("Presentation ID to copy"),
31116
- title: external_exports.string().describe("Title for the new copy"),
31117
- parent: external_exports.string().optional().describe("Destination folder ID"),
31118
- account: accountParam
31119
- }
31120
- }, async ({ presentationId, title, parent, account }) => {
31121
- const args = ["slides", "copy", presentationId, title];
31122
- if (parent) args.push(`--parent=${parent}`);
31123
- return runOrDiagnose(args, { account });
31124
- });
31125
31175
  server2.registerTool("gog_slides_add_slide", {
31126
31176
  description: "Add a new slide to a presentation from a local image, with optional speaker notes.",
31127
31177
  inputSchema: {
@@ -31139,16 +31189,6 @@ function registerSlidesTools(server2) {
31139
31189
  if (before) args.push(`--before=${before}`);
31140
31190
  return runOrDiagnose(args, { account });
31141
31191
  });
31142
- server2.registerTool("gog_slides_list_slides", {
31143
- description: "List slides in a Google Slides presentation.",
31144
- annotations: { readOnlyHint: true },
31145
- inputSchema: {
31146
- presentationId: external_exports.string().describe("Presentation ID"),
31147
- account: accountParam
31148
- }
31149
- }, async ({ presentationId, account }) => {
31150
- return runOrDiagnose(["slides", "list-slides", presentationId], { account });
31151
- });
31152
31192
  server2.registerTool("gog_slides_delete_slide", {
31153
31193
  description: "Delete a slide from a Google Slides presentation.",
31154
31194
  annotations: { destructiveHint: true },
@@ -31160,17 +31200,6 @@ function registerSlidesTools(server2) {
31160
31200
  }, async ({ presentationId, slideId, account }) => {
31161
31201
  return runOrDiagnose(["slides", "delete-slide", presentationId, slideId], { account });
31162
31202
  });
31163
- server2.registerTool("gog_slides_read_slide", {
31164
- description: "Read the content of a slide (text, shapes, speaker notes).",
31165
- annotations: { readOnlyHint: true },
31166
- inputSchema: {
31167
- presentationId: external_exports.string().describe("Presentation ID"),
31168
- slideId: external_exports.string().describe("Slide ID to read"),
31169
- account: accountParam
31170
- }
31171
- }, async ({ presentationId, slideId, account }) => {
31172
- return runOrDiagnose(["slides", "read-slide", presentationId, slideId], { account });
31173
- });
31174
31203
  server2.registerTool("gog_slides_update_notes", {
31175
31204
  description: "Update the speaker notes on a slide (inline text or from a file).",
31176
31205
  annotations: { destructiveHint: true },
@@ -31204,29 +31233,6 @@ function registerSlidesTools(server2) {
31204
31233
  if (notesFile) args.push(`--notes-file=${notesFile}`);
31205
31234
  return runOrDiagnose(args, { account });
31206
31235
  });
31207
- server2.registerTool("gog_slides_run", {
31208
- description: "Run any gog slides subcommand not covered by the other tools. Run `gog slides --help` for the full list of subcommands, or `gog slides <subcommand> --help` for flags on a specific subcommand.",
31209
- inputSchema: {
31210
- subcommand: external_exports.string().describe("The gog slides subcommand to run"),
31211
- args: external_exports.array(external_exports.string()).describe("Additional positional args and flags"),
31212
- account: accountParam
31213
- }
31214
- }, async ({ subcommand, args, account }) => {
31215
- return runOrDiagnose(["slides", subcommand, ...args], { account });
31216
- });
31217
- }
31218
-
31219
- // ../gogcli-mcp/src/server.ts
31220
- var VERSION = true ? "2.0.4" : "0.0.0";
31221
- function createServer(options) {
31222
- return new McpServer({
31223
- name: options?.name ?? "gogcli",
31224
- version: options?.version ?? VERSION
31225
- });
31226
- }
31227
-
31228
- // src/tools/slides-extra.ts
31229
- function registerExtraSlidesTools(_server) {
31230
31236
  }
31231
31237
 
31232
31238
  // src/index.ts
package/manifest.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifest_version": "0.3",
4
4
  "name": "gogcli-mcp-slides",
5
5
  "display_name": "gogcli (Slides)",
6
- "version": "2.0.4",
6
+ "version": "2.0.7",
7
7
  "description": "Extended Google Slides for Claude via gogcli — auth + full Slides support (create, edit, export, templates, markdown)",
8
8
  "author": {
9
9
  "name": "Chris Hall",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gogcli-mcp-slides",
3
- "version": "2.0.4",
3
+ "version": "2.0.7",
4
4
  "mcpName": "io.github.chrischall/gogcli-mcp-slides",
5
5
  "description": "Extended Google Slides MCP server via gogcli — auth + full Slides support",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
package/server.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "source": "github",
8
8
  "subfolder": "packages/gogcli-mcp-slides"
9
9
  },
10
- "version": "2.0.4",
10
+ "version": "2.0.7",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "gogcli-mcp-slides",
15
- "version": "2.0.4",
15
+ "version": "2.0.7",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },
@@ -1,5 +1,113 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod';
3
+ import { accountParam, runOrDiagnose } from '../../../gogcli-mcp/src/lib.js';
2
4
 
3
- export function registerExtraSlidesTools(_server: McpServer): void {
4
- /* no extras yet */
5
+ export function registerExtraSlidesTools(server: McpServer): void {
6
+ server.registerTool('gog_slides_create_from_markdown', {
7
+ description: 'Create a new Google Slides presentation from markdown content (inline or from a file).',
8
+ inputSchema: {
9
+ title: z.string().describe('Presentation title'),
10
+ content: z.string().optional().describe('Inline markdown content'),
11
+ contentFile: z.string().optional().describe('Path to a markdown file'),
12
+ parent: z.string().optional().describe('Destination folder ID'),
13
+ debug: z.boolean().optional().describe('Enable debug output'),
14
+ account: accountParam,
15
+ },
16
+ }, async ({ title, content, contentFile, parent, debug, account }) => {
17
+ const args = ['slides', 'create-from-markdown', title];
18
+ if (content) args.push(`--content=${content}`);
19
+ if (contentFile) args.push(`--content-file=${contentFile}`);
20
+ if (parent) args.push(`--parent=${parent}`);
21
+ if (debug) args.push('--debug');
22
+ return runOrDiagnose(args, { account });
23
+ });
24
+
25
+ server.registerTool('gog_slides_create_from_template', {
26
+ description: 'Create a new Google Slides presentation from a template, with optional placeholder replacements.',
27
+ inputSchema: {
28
+ templateId: z.string().describe('Template presentation ID'),
29
+ title: z.string().describe('New presentation title'),
30
+ replacements: z.record(z.string(), z.string()).optional().describe('Placeholder replacements as a key/value object (emitted as --replace=k=v for each entry)'),
31
+ replacementsFile: z.string().optional().describe('Path to a JSON file containing replacements'),
32
+ parent: z.string().optional().describe('Destination folder ID'),
33
+ exact: z.boolean().optional().describe('Require exact placeholder matches'),
34
+ account: accountParam,
35
+ },
36
+ }, async ({ templateId, title, replacements, replacementsFile, parent, exact, account }) => {
37
+ const args = ['slides', 'create-from-template', templateId, title];
38
+ if (replacements) {
39
+ for (const [k, v] of Object.entries(replacements)) {
40
+ args.push(`--replace=${k}=${v}`);
41
+ }
42
+ }
43
+ if (replacementsFile) args.push(`--replacements=${replacementsFile}`);
44
+ if (parent) args.push(`--parent=${parent}`);
45
+ if (exact) args.push('--exact');
46
+ return runOrDiagnose(args, { account });
47
+ });
48
+
49
+ server.registerTool('gog_slides_add_slide', {
50
+ description: 'Add a new slide to a presentation from a local image, with optional speaker notes.',
51
+ inputSchema: {
52
+ presentationId: z.string().describe('Presentation ID'),
53
+ image: z.string().describe('Path to the local image file'),
54
+ notes: z.string().optional().describe('Speaker notes text'),
55
+ notesFile: z.string().optional().describe('Path to a file containing speaker notes'),
56
+ before: z.string().optional().describe('Insert before this slide ID (default: append at end)'),
57
+ account: accountParam,
58
+ },
59
+ }, async ({ presentationId, image, notes, notesFile, before, account }) => {
60
+ const args = ['slides', 'add-slide', presentationId, image];
61
+ if (notes) args.push(`--notes=${notes}`);
62
+ if (notesFile) args.push(`--notes-file=${notesFile}`);
63
+ if (before) args.push(`--before=${before}`);
64
+ return runOrDiagnose(args, { account });
65
+ });
66
+
67
+ server.registerTool('gog_slides_delete_slide', {
68
+ description: 'Delete a slide from a Google Slides presentation.',
69
+ annotations: { destructiveHint: true },
70
+ inputSchema: {
71
+ presentationId: z.string().describe('Presentation ID'),
72
+ slideId: z.string().describe('Slide ID to delete'),
73
+ account: accountParam,
74
+ },
75
+ }, async ({ presentationId, slideId, account }) => {
76
+ return runOrDiagnose(['slides', 'delete-slide', presentationId, slideId], { account });
77
+ });
78
+
79
+ server.registerTool('gog_slides_update_notes', {
80
+ description: 'Update the speaker notes on a slide (inline text or from a file).',
81
+ annotations: { destructiveHint: true },
82
+ inputSchema: {
83
+ presentationId: z.string().describe('Presentation ID'),
84
+ slideId: z.string().describe('Slide ID'),
85
+ notes: z.string().optional().describe('New speaker notes text'),
86
+ notesFile: z.string().optional().describe('Path to a file containing new speaker notes'),
87
+ account: accountParam,
88
+ },
89
+ }, async ({ presentationId, slideId, notes, notesFile, account }) => {
90
+ const args = ['slides', 'update-notes', presentationId, slideId];
91
+ if (notes) args.push(`--notes=${notes}`);
92
+ if (notesFile) args.push(`--notes-file=${notesFile}`);
93
+ return runOrDiagnose(args, { account });
94
+ });
95
+
96
+ server.registerTool('gog_slides_replace_slide', {
97
+ description: 'Replace the image content of an existing slide, with optional speaker notes.',
98
+ annotations: { destructiveHint: true },
99
+ inputSchema: {
100
+ presentationId: z.string().describe('Presentation ID'),
101
+ slideId: z.string().describe('Slide ID to replace'),
102
+ image: z.string().describe('Path to the new local image file'),
103
+ notes: z.string().optional().describe('Speaker notes text'),
104
+ notesFile: z.string().optional().describe('Path to a file containing speaker notes'),
105
+ account: accountParam,
106
+ },
107
+ }, async ({ presentationId, slideId, image, notes, notesFile, account }) => {
108
+ const args = ['slides', 'replace-slide', presentationId, slideId, image];
109
+ if (notes) args.push(`--notes=${notes}`);
110
+ if (notesFile) args.push(`--notes-file=${notesFile}`);
111
+ return runOrDiagnose(args, { account });
112
+ });
5
113
  }
@@ -1,10 +1,220 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
2
  import { registerExtraSlidesTools } from '../../src/tools/slides-extra.js';
3
+ import * as lib from '../../../gogcli-mcp/src/lib.js';
4
+ import { setupExtrasHandlers, toText, type ToolHandler } from '../../../gogcli-mcp/tests/helpers/extras-harness.js';
4
5
 
5
- describe('registerExtraSlidesTools', () => {
6
- it('does not throw when called (no extras yet)', () => {
7
- const server = new McpServer({ name: 'test', version: '0.0.0' });
8
- expect(() => registerExtraSlidesTools(server)).not.toThrow();
6
+ vi.mock('../../../gogcli-mcp/src/lib.js', async (importOriginal) => {
7
+ const actual = await importOriginal<typeof lib>();
8
+ return {
9
+ ...actual,
10
+ runOrDiagnose: vi.fn(),
11
+ };
12
+ });
13
+
14
+ let handlers: Map<string, ToolHandler>;
15
+
16
+ beforeEach(() => {
17
+ vi.clearAllMocks();
18
+ vi.mocked(lib.runOrDiagnose).mockResolvedValue(toText('{}'));
19
+ handlers = setupExtrasHandlers(registerExtraSlidesTools);
20
+ });
21
+
22
+ describe('gog_slides_create_from_markdown', () => {
23
+ it('calls runOrDiagnose with title only', async () => {
24
+ await handlers.get('gog_slides_create_from_markdown')!({ title: 'Deck' });
25
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
26
+ ['slides', 'create-from-markdown', 'Deck'],
27
+ { account: undefined },
28
+ );
29
+ });
30
+
31
+ it('passes all optional flags', async () => {
32
+ await handlers.get('gog_slides_create_from_markdown')!({
33
+ title: 'Deck',
34
+ content: '# Slide 1',
35
+ contentFile: '/tmp/deck.md',
36
+ parent: 'folder1',
37
+ debug: true,
38
+ });
39
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
40
+ [
41
+ 'slides', 'create-from-markdown', 'Deck',
42
+ '--content=# Slide 1',
43
+ '--content-file=/tmp/deck.md',
44
+ '--parent=folder1',
45
+ '--debug',
46
+ ],
47
+ { account: undefined },
48
+ );
49
+ });
50
+
51
+ it('omits --debug when false', async () => {
52
+ await handlers.get('gog_slides_create_from_markdown')!({ title: 'Deck', debug: false });
53
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
54
+ ['slides', 'create-from-markdown', 'Deck'],
55
+ { account: undefined },
56
+ );
57
+ });
58
+ });
59
+
60
+ describe('gog_slides_create_from_template', () => {
61
+ it('calls runOrDiagnose with templateId and title only', async () => {
62
+ await handlers.get('gog_slides_create_from_template')!({ templateId: 'tpl1', title: 'Deck' });
63
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
64
+ ['slides', 'create-from-template', 'tpl1', 'Deck'],
65
+ { account: undefined },
66
+ );
67
+ });
68
+
69
+ it('passes --replace for a single replacement entry', async () => {
70
+ await handlers.get('gog_slides_create_from_template')!({
71
+ templateId: 'tpl1',
72
+ title: 'Deck',
73
+ replacements: { name: 'Alice' },
74
+ });
75
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
76
+ ['slides', 'create-from-template', 'tpl1', 'Deck', '--replace=name=Alice'],
77
+ { account: undefined },
78
+ );
79
+ });
80
+
81
+ it('passes --replace for each entry in replacements', async () => {
82
+ await handlers.get('gog_slides_create_from_template')!({
83
+ templateId: 'tpl1',
84
+ title: 'Deck',
85
+ replacements: { name: 'Alice', company: 'Acme' },
86
+ });
87
+ const call = vi.mocked(lib.runOrDiagnose).mock.calls[0]!;
88
+ expect(call[0]).toEqual(expect.arrayContaining(['--replace=name=Alice', '--replace=company=Acme']));
89
+ expect(call[1]).toEqual({ account: undefined });
90
+ });
91
+
92
+ it('passes --replacements, --parent, and --exact', async () => {
93
+ await handlers.get('gog_slides_create_from_template')!({
94
+ templateId: 'tpl1',
95
+ title: 'Deck',
96
+ replacementsFile: '/tmp/r.json',
97
+ parent: 'folder1',
98
+ exact: true,
99
+ });
100
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
101
+ [
102
+ 'slides', 'create-from-template', 'tpl1', 'Deck',
103
+ '--replacements=/tmp/r.json',
104
+ '--parent=folder1',
105
+ '--exact',
106
+ ],
107
+ { account: undefined },
108
+ );
109
+ });
110
+
111
+ it('omits --exact when false', async () => {
112
+ await handlers.get('gog_slides_create_from_template')!({
113
+ templateId: 'tpl1',
114
+ title: 'Deck',
115
+ exact: false,
116
+ });
117
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
118
+ ['slides', 'create-from-template', 'tpl1', 'Deck'],
119
+ { account: undefined },
120
+ );
121
+ });
122
+ });
123
+
124
+ describe('gog_slides_add_slide', () => {
125
+ it('calls runOrDiagnose with presentationId and image', async () => {
126
+ await handlers.get('gog_slides_add_slide')!({ presentationId: 'p1', image: '/tmp/img.png' });
127
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
128
+ ['slides', 'add-slide', 'p1', '/tmp/img.png'],
129
+ { account: undefined },
130
+ );
131
+ });
132
+
133
+ it('passes --notes, --notes-file, and --before', async () => {
134
+ await handlers.get('gog_slides_add_slide')!({
135
+ presentationId: 'p1',
136
+ image: '/tmp/img.png',
137
+ notes: 'Speaker note',
138
+ notesFile: '/tmp/notes.txt',
139
+ before: 'slide5',
140
+ });
141
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
142
+ [
143
+ 'slides', 'add-slide', 'p1', '/tmp/img.png',
144
+ '--notes=Speaker note',
145
+ '--notes-file=/tmp/notes.txt',
146
+ '--before=slide5',
147
+ ],
148
+ { account: undefined },
149
+ );
150
+ });
151
+ });
152
+
153
+ describe('gog_slides_delete_slide', () => {
154
+ it('calls runOrDiagnose with presentationId and slideId', async () => {
155
+ await handlers.get('gog_slides_delete_slide')!({ presentationId: 'p1', slideId: 's1' });
156
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
157
+ ['slides', 'delete-slide', 'p1', 's1'],
158
+ { account: undefined },
159
+ );
160
+ });
161
+ });
162
+
163
+ describe('gog_slides_update_notes', () => {
164
+ it('calls runOrDiagnose with presentationId and slideId', async () => {
165
+ await handlers.get('gog_slides_update_notes')!({ presentationId: 'p1', slideId: 's1' });
166
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
167
+ ['slides', 'update-notes', 'p1', 's1'],
168
+ { account: undefined },
169
+ );
170
+ });
171
+
172
+ it('passes --notes and --notes-file when provided', async () => {
173
+ await handlers.get('gog_slides_update_notes')!({
174
+ presentationId: 'p1',
175
+ slideId: 's1',
176
+ notes: 'speak clearly',
177
+ notesFile: '/tmp/n.txt',
178
+ });
179
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
180
+ [
181
+ 'slides', 'update-notes', 'p1', 's1',
182
+ '--notes=speak clearly',
183
+ '--notes-file=/tmp/n.txt',
184
+ ],
185
+ { account: undefined },
186
+ );
187
+ });
188
+ });
189
+
190
+ describe('gog_slides_replace_slide', () => {
191
+ it('calls runOrDiagnose with presentationId, slideId, and image', async () => {
192
+ await handlers.get('gog_slides_replace_slide')!({
193
+ presentationId: 'p1',
194
+ slideId: 's1',
195
+ image: '/tmp/img.png',
196
+ });
197
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
198
+ ['slides', 'replace-slide', 'p1', 's1', '/tmp/img.png'],
199
+ { account: undefined },
200
+ );
201
+ });
202
+
203
+ it('passes --notes and --notes-file when provided', async () => {
204
+ await handlers.get('gog_slides_replace_slide')!({
205
+ presentationId: 'p1',
206
+ slideId: 's1',
207
+ image: '/tmp/img.png',
208
+ notes: 'updated',
209
+ notesFile: '/tmp/n.txt',
210
+ });
211
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
212
+ [
213
+ 'slides', 'replace-slide', 'p1', 's1', '/tmp/img.png',
214
+ '--notes=updated',
215
+ '--notes-file=/tmp/n.txt',
216
+ ],
217
+ { account: undefined },
218
+ );
9
219
  });
10
220
  });