gogcli-mcp-calendar 2.2.0 → 2.3.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/dist/index.js CHANGED
@@ -31361,7 +31361,7 @@ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
31361
31361
  );
31362
31362
 
31363
31363
  // ../gogcli-mcp/src/server.ts
31364
- var VERSION = true ? "2.2.0" : "0.0.0";
31364
+ var VERSION = true ? "2.3.0" : "0.0.0";
31365
31365
  function createServer(options) {
31366
31366
  return new McpServer({
31367
31367
  name: options?.name ?? "gogcli",
@@ -31465,6 +31465,132 @@ function registerExtraCalendarTools(server2) {
31465
31465
  if (alias) args.push(`--alias=${alias}`);
31466
31466
  return runOrDiagnose(args, {});
31467
31467
  });
31468
+ server2.registerTool("gog_calendar_calendars", {
31469
+ description: "List the calendars in your calendar list (id, summary, access role, primary flag).",
31470
+ annotations: { readOnlyHint: true },
31471
+ inputSchema: {
31472
+ max: external_exports.number().optional().describe("Max results (default: 100)"),
31473
+ page: external_exports.string().optional().describe("Page token"),
31474
+ all: external_exports.boolean().optional().describe("Fetch all pages"),
31475
+ account: accountParam
31476
+ }
31477
+ }, async ({ max, page, all, account }) => {
31478
+ const args = ["calendar", "calendars"];
31479
+ if (max !== void 0) args.push(`--max=${max}`);
31480
+ if (page) args.push(`--page=${page}`);
31481
+ if (all) args.push("--all");
31482
+ return runOrDiagnose(args, { account });
31483
+ });
31484
+ server2.registerTool("gog_calendar_search", {
31485
+ description: "Full-text search for events matching a query string, with optional time filters.",
31486
+ annotations: { readOnlyHint: true },
31487
+ inputSchema: {
31488
+ query: external_exports.string().describe("Search query"),
31489
+ from: external_exports.string().optional().describe("Start time (RFC3339, date, or relative: now, today, tomorrow, monday)"),
31490
+ to: external_exports.string().optional().describe("End time (RFC3339, date, or relative: now, today, tomorrow, monday)"),
31491
+ today: external_exports.boolean().optional().describe("Today only"),
31492
+ tomorrow: external_exports.boolean().optional().describe("Tomorrow only"),
31493
+ week: external_exports.boolean().optional().describe("This week (uses weekStart, default Mon)"),
31494
+ days: external_exports.number().optional().describe("Next N days"),
31495
+ weekStart: external_exports.string().optional().describe("Week start day for week (sun, mon, ...)"),
31496
+ calendar: external_exports.string().optional().describe("Calendar ID (default: primary)"),
31497
+ max: external_exports.number().optional().describe("Max results (default: 25)"),
31498
+ account: accountParam
31499
+ }
31500
+ }, async ({ query, from, to, today, tomorrow, week, days, weekStart, calendar, max, account }) => {
31501
+ const args = ["calendar", "search", query];
31502
+ if (from) args.push(`--from=${from}`);
31503
+ if (to) args.push(`--to=${to}`);
31504
+ if (today) args.push("--today");
31505
+ if (tomorrow) args.push("--tomorrow");
31506
+ if (week) args.push("--week");
31507
+ if (days !== void 0) args.push(`--days=${days}`);
31508
+ if (weekStart) args.push(`--week-start=${weekStart}`);
31509
+ if (calendar) args.push(`--calendar=${calendar}`);
31510
+ if (max !== void 0) args.push(`--max=${max}`);
31511
+ return runOrDiagnose(args, { account });
31512
+ });
31513
+ server2.registerTool("gog_calendar_freebusy", {
31514
+ description: "Query free/busy intervals for one or more calendars over a time window.",
31515
+ annotations: { readOnlyHint: true },
31516
+ inputSchema: {
31517
+ from: external_exports.string().describe("Start time (RFC3339, required)"),
31518
+ to: external_exports.string().describe("End time (RFC3339, required)"),
31519
+ calendarIds: external_exports.string().optional().describe("Comma-separated calendar IDs, names, or indices"),
31520
+ all: external_exports.boolean().optional().describe("Query all calendars"),
31521
+ account: accountParam
31522
+ }
31523
+ }, async ({ from, to, calendarIds, all, account }) => {
31524
+ const args = ["calendar", "freebusy"];
31525
+ if (calendarIds) args.push(calendarIds);
31526
+ args.push(`--from=${from}`);
31527
+ args.push(`--to=${to}`);
31528
+ if (all) args.push("--all");
31529
+ return runOrDiagnose(args, { account });
31530
+ });
31531
+ server2.registerTool("gog_calendar_colors", {
31532
+ description: "Show the available calendar and event color palette (color IDs to hex values).",
31533
+ annotations: { readOnlyHint: true },
31534
+ inputSchema: {
31535
+ account: accountParam
31536
+ }
31537
+ }, async ({ account }) => {
31538
+ return runOrDiagnose(["calendar", "colors"], { account });
31539
+ });
31540
+ server2.registerTool("gog_calendar_acl", {
31541
+ description: "List the access control list (sharing rules) for a calendar.",
31542
+ annotations: { readOnlyHint: true },
31543
+ inputSchema: {
31544
+ calendarId: external_exports.string().describe("Calendar ID"),
31545
+ max: external_exports.number().optional().describe("Max results (default: 100)"),
31546
+ page: external_exports.string().optional().describe("Page token"),
31547
+ all: external_exports.boolean().optional().describe("Fetch all pages"),
31548
+ account: accountParam
31549
+ }
31550
+ }, async ({ calendarId, max, page, all, account }) => {
31551
+ const args = ["calendar", "acl", calendarId];
31552
+ if (max !== void 0) args.push(`--max=${max}`);
31553
+ if (page) args.push(`--page=${page}`);
31554
+ if (all) args.push("--all");
31555
+ return runOrDiagnose(args, { account });
31556
+ });
31557
+ server2.registerTool("gog_calendar_move", {
31558
+ description: "Move an event from one calendar to another; the destination calendar becomes the organizer.",
31559
+ inputSchema: {
31560
+ calendarId: external_exports.string().describe("Source calendar ID"),
31561
+ eventId: external_exports.string().describe("Event ID"),
31562
+ destinationCalendarId: external_exports.string().describe("Destination calendar ID that becomes the event organizer"),
31563
+ sendUpdates: external_exports.enum(["all", "externalOnly", "none"]).optional().describe("Notification mode (default: none)"),
31564
+ account: accountParam
31565
+ }
31566
+ }, async ({ calendarId, eventId, destinationCalendarId, sendUpdates, account }) => {
31567
+ const args = ["calendar", "move", calendarId, eventId, destinationCalendarId];
31568
+ if (sendUpdates) args.push(`--send-updates=${sendUpdates}`);
31569
+ return runOrDiagnose(args, { account });
31570
+ });
31571
+ server2.registerTool("gog_calendar_out_of_office", {
31572
+ description: "Create an Out of Office event that auto-declines invitations during the block.",
31573
+ inputSchema: {
31574
+ from: external_exports.string().describe("Start date or datetime (RFC3339 or YYYY-MM-DD)"),
31575
+ to: external_exports.string().describe("End date or datetime (RFC3339 or YYYY-MM-DD)"),
31576
+ calendarId: external_exports.string().optional().describe("Calendar ID (default: primary)"),
31577
+ summary: external_exports.string().optional().describe('Out of office title (default: "Out of office")'),
31578
+ autoDecline: external_exports.enum(["none", "all", "new"]).optional().describe("Auto-decline mode (default: all)"),
31579
+ declineMessage: external_exports.string().optional().describe("Message for declined invitations"),
31580
+ allDay: external_exports.boolean().optional().describe("Create as an all-day event"),
31581
+ account: accountParam
31582
+ }
31583
+ }, async ({ from, to, calendarId, summary, autoDecline, declineMessage, allDay, account }) => {
31584
+ const args = ["calendar", "out-of-office"];
31585
+ if (calendarId) args.push(calendarId);
31586
+ args.push(`--from=${from}`);
31587
+ args.push(`--to=${to}`);
31588
+ if (summary) args.push(`--summary=${summary}`);
31589
+ if (autoDecline) args.push(`--auto-decline=${autoDecline}`);
31590
+ if (declineMessage) args.push(`--decline-message=${declineMessage}`);
31591
+ if (allDay) args.push("--all-day");
31592
+ return runOrDiagnose(args, { account });
31593
+ });
31468
31594
  server2.registerTool("gog_meet_participants", {
31469
31595
  description: "List participants from the latest (or a specific) Meet call.",
31470
31596
  annotations: { readOnlyHint: true },
package/manifest.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifest_version": "0.3",
4
4
  "name": "gogcli-mcp-calendar",
5
5
  "display_name": "gogcli (Calendar)",
6
- "version": "2.2.0",
6
+ "version": "2.3.0",
7
7
  "description": "Extended Google Calendar for Claude via gogcli — auth + Calendar events + Meet space management",
8
8
  "author": {
9
9
  "name": "Chris Hall",
@@ -102,6 +102,34 @@
102
102
  "name": "gog_calendar_run",
103
103
  "description": "Run any gog calendar subcommand (escape hatch)"
104
104
  },
105
+ {
106
+ "name": "gog_calendar_calendars",
107
+ "description": "List the calendars in your calendar list"
108
+ },
109
+ {
110
+ "name": "gog_calendar_search",
111
+ "description": "Full-text search for events with optional time filters"
112
+ },
113
+ {
114
+ "name": "gog_calendar_freebusy",
115
+ "description": "Query free/busy intervals for one or more calendars"
116
+ },
117
+ {
118
+ "name": "gog_calendar_colors",
119
+ "description": "Show the available calendar and event color palette"
120
+ },
121
+ {
122
+ "name": "gog_calendar_acl",
123
+ "description": "List the access control list (sharing rules) for a calendar"
124
+ },
125
+ {
126
+ "name": "gog_calendar_move",
127
+ "description": "Move an event to another calendar"
128
+ },
129
+ {
130
+ "name": "gog_calendar_out_of_office",
131
+ "description": "Create an Out of Office event that auto-declines invitations"
132
+ },
105
133
  {
106
134
  "name": "gog_meet_create",
107
135
  "description": "Create a Google Meet space"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gogcli-mcp-calendar",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "mcpName": "io.github.chrischall/gogcli-mcp-calendar",
5
5
  "description": "Extended Google Calendar + Meet MCP server via gogcli — auth + Calendar events + Meet space management",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -110,6 +110,141 @@ export function registerExtraCalendarTools(server: McpServer): void {
110
110
  return runOrDiagnose(args, {});
111
111
  });
112
112
 
113
+ // --- gog 0.19.0 calendar reads & CRUD ---
114
+
115
+ server.registerTool('gog_calendar_calendars', {
116
+ description: 'List the calendars in your calendar list (id, summary, access role, primary flag).',
117
+ annotations: { readOnlyHint: true },
118
+ inputSchema: {
119
+ max: z.number().optional().describe('Max results (default: 100)'),
120
+ page: z.string().optional().describe('Page token'),
121
+ all: z.boolean().optional().describe('Fetch all pages'),
122
+ account: accountParam,
123
+ },
124
+ }, async ({ max, page, all, account }) => {
125
+ const args = ['calendar', 'calendars'];
126
+ if (max !== undefined) args.push(`--max=${max}`);
127
+ if (page) args.push(`--page=${page}`);
128
+ if (all) args.push('--all');
129
+ return runOrDiagnose(args, { account });
130
+ });
131
+
132
+ server.registerTool('gog_calendar_search', {
133
+ description: 'Full-text search for events matching a query string, with optional time filters.',
134
+ annotations: { readOnlyHint: true },
135
+ inputSchema: {
136
+ query: z.string().describe('Search query'),
137
+ from: z.string().optional().describe('Start time (RFC3339, date, or relative: now, today, tomorrow, monday)'),
138
+ to: z.string().optional().describe('End time (RFC3339, date, or relative: now, today, tomorrow, monday)'),
139
+ today: z.boolean().optional().describe('Today only'),
140
+ tomorrow: z.boolean().optional().describe('Tomorrow only'),
141
+ week: z.boolean().optional().describe('This week (uses weekStart, default Mon)'),
142
+ days: z.number().optional().describe('Next N days'),
143
+ weekStart: z.string().optional().describe('Week start day for week (sun, mon, ...)'),
144
+ calendar: z.string().optional().describe('Calendar ID (default: primary)'),
145
+ max: z.number().optional().describe('Max results (default: 25)'),
146
+ account: accountParam,
147
+ },
148
+ }, async ({ query, from, to, today, tomorrow, week, days, weekStart, calendar, max, account }) => {
149
+ const args = ['calendar', 'search', query];
150
+ if (from) args.push(`--from=${from}`);
151
+ if (to) args.push(`--to=${to}`);
152
+ if (today) args.push('--today');
153
+ if (tomorrow) args.push('--tomorrow');
154
+ if (week) args.push('--week');
155
+ if (days !== undefined) args.push(`--days=${days}`);
156
+ if (weekStart) args.push(`--week-start=${weekStart}`);
157
+ if (calendar) args.push(`--calendar=${calendar}`);
158
+ if (max !== undefined) args.push(`--max=${max}`);
159
+ return runOrDiagnose(args, { account });
160
+ });
161
+
162
+ server.registerTool('gog_calendar_freebusy', {
163
+ description: 'Query free/busy intervals for one or more calendars over a time window.',
164
+ annotations: { readOnlyHint: true },
165
+ inputSchema: {
166
+ from: z.string().describe('Start time (RFC3339, required)'),
167
+ to: z.string().describe('End time (RFC3339, required)'),
168
+ calendarIds: z.string().optional().describe('Comma-separated calendar IDs, names, or indices'),
169
+ all: z.boolean().optional().describe('Query all calendars'),
170
+ account: accountParam,
171
+ },
172
+ }, async ({ from, to, calendarIds, all, account }) => {
173
+ const args = ['calendar', 'freebusy'];
174
+ if (calendarIds) args.push(calendarIds);
175
+ args.push(`--from=${from}`);
176
+ args.push(`--to=${to}`);
177
+ if (all) args.push('--all');
178
+ return runOrDiagnose(args, { account });
179
+ });
180
+
181
+ server.registerTool('gog_calendar_colors', {
182
+ description: 'Show the available calendar and event color palette (color IDs to hex values).',
183
+ annotations: { readOnlyHint: true },
184
+ inputSchema: {
185
+ account: accountParam,
186
+ },
187
+ }, async ({ account }) => {
188
+ return runOrDiagnose(['calendar', 'colors'], { account });
189
+ });
190
+
191
+ server.registerTool('gog_calendar_acl', {
192
+ description: 'List the access control list (sharing rules) for a calendar.',
193
+ annotations: { readOnlyHint: true },
194
+ inputSchema: {
195
+ calendarId: z.string().describe('Calendar ID'),
196
+ max: z.number().optional().describe('Max results (default: 100)'),
197
+ page: z.string().optional().describe('Page token'),
198
+ all: z.boolean().optional().describe('Fetch all pages'),
199
+ account: accountParam,
200
+ },
201
+ }, async ({ calendarId, max, page, all, account }) => {
202
+ const args = ['calendar', 'acl', calendarId];
203
+ if (max !== undefined) args.push(`--max=${max}`);
204
+ if (page) args.push(`--page=${page}`);
205
+ if (all) args.push('--all');
206
+ return runOrDiagnose(args, { account });
207
+ });
208
+
209
+ server.registerTool('gog_calendar_move', {
210
+ description: 'Move an event from one calendar to another; the destination calendar becomes the organizer.',
211
+ inputSchema: {
212
+ calendarId: z.string().describe('Source calendar ID'),
213
+ eventId: z.string().describe('Event ID'),
214
+ destinationCalendarId: z.string().describe('Destination calendar ID that becomes the event organizer'),
215
+ sendUpdates: z.enum(['all', 'externalOnly', 'none']).optional().describe('Notification mode (default: none)'),
216
+ account: accountParam,
217
+ },
218
+ }, async ({ calendarId, eventId, destinationCalendarId, sendUpdates, account }) => {
219
+ const args = ['calendar', 'move', calendarId, eventId, destinationCalendarId];
220
+ if (sendUpdates) args.push(`--send-updates=${sendUpdates}`);
221
+ return runOrDiagnose(args, { account });
222
+ });
223
+
224
+ server.registerTool('gog_calendar_out_of_office', {
225
+ description: 'Create an Out of Office event that auto-declines invitations during the block.',
226
+ inputSchema: {
227
+ from: z.string().describe('Start date or datetime (RFC3339 or YYYY-MM-DD)'),
228
+ to: z.string().describe('End date or datetime (RFC3339 or YYYY-MM-DD)'),
229
+ calendarId: z.string().optional().describe('Calendar ID (default: primary)'),
230
+ summary: z.string().optional().describe('Out of office title (default: "Out of office")'),
231
+ autoDecline: z.enum(['none', 'all', 'new']).optional().describe('Auto-decline mode (default: all)'),
232
+ declineMessage: z.string().optional().describe('Message for declined invitations'),
233
+ allDay: z.boolean().optional().describe('Create as an all-day event'),
234
+ account: accountParam,
235
+ },
236
+ }, async ({ from, to, calendarId, summary, autoDecline, declineMessage, allDay, account }) => {
237
+ const args = ['calendar', 'out-of-office'];
238
+ if (calendarId) args.push(calendarId);
239
+ args.push(`--from=${from}`);
240
+ args.push(`--to=${to}`);
241
+ if (summary) args.push(`--summary=${summary}`);
242
+ if (autoDecline) args.push(`--auto-decline=${autoDecline}`);
243
+ if (declineMessage) args.push(`--decline-message=${declineMessage}`);
244
+ if (allDay) args.push('--all-day');
245
+ return runOrDiagnose(args, { account });
246
+ });
247
+
113
248
  server.registerTool('gog_meet_participants', {
114
249
  description: 'List participants from the latest (or a specific) Meet call.',
115
250
  annotations: { readOnlyHint: true },
@@ -143,6 +143,183 @@ describe('gog_zoom_auth_doctor', () => {
143
143
  });
144
144
  });
145
145
 
146
+ // --- gog 0.19.0 calendar reads & CRUD ---
147
+
148
+ describe('gog_calendar_calendars', () => {
149
+ it('calls runOrDiagnose with no flags', async () => {
150
+ await handlers.get('gog_calendar_calendars')!({});
151
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'calendars'], { account: undefined });
152
+ });
153
+
154
+ it('passes pagination flags', async () => {
155
+ await handlers.get('gog_calendar_calendars')!({ max: 50, page: 'tok', all: true });
156
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
157
+ ['calendar', 'calendars', '--max=50', '--page=tok', '--all'],
158
+ { account: undefined },
159
+ );
160
+ });
161
+
162
+ it('omits --all when false', async () => {
163
+ await handlers.get('gog_calendar_calendars')!({ all: false });
164
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'calendars'], { account: undefined });
165
+ });
166
+ });
167
+
168
+ describe('gog_calendar_search', () => {
169
+ it('calls runOrDiagnose with just the query', async () => {
170
+ await handlers.get('gog_calendar_search')!({ query: 'standup' });
171
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'search', 'standup'], { account: undefined });
172
+ });
173
+
174
+ it('passes all filter flags when provided', async () => {
175
+ await handlers.get('gog_calendar_search')!({
176
+ query: 'standup',
177
+ from: 'today',
178
+ to: 'tomorrow',
179
+ today: true,
180
+ tomorrow: true,
181
+ week: true,
182
+ days: 7,
183
+ weekStart: 'sun',
184
+ calendar: 'primary',
185
+ max: 10,
186
+ });
187
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
188
+ [
189
+ 'calendar', 'search', 'standup',
190
+ '--from=today', '--to=tomorrow',
191
+ '--today', '--tomorrow', '--week',
192
+ '--days=7', '--week-start=sun',
193
+ '--calendar=primary', '--max=10',
194
+ ],
195
+ { account: undefined },
196
+ );
197
+ });
198
+
199
+ it('omits boolean flags when false', async () => {
200
+ await handlers.get('gog_calendar_search')!({
201
+ query: 'standup', today: false, tomorrow: false, week: false,
202
+ });
203
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'search', 'standup'], { account: undefined });
204
+ });
205
+ });
206
+
207
+ describe('gog_calendar_freebusy', () => {
208
+ it('calls runOrDiagnose with required from/to only', async () => {
209
+ await handlers.get('gog_calendar_freebusy')!({ from: 'A', to: 'B' });
210
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
211
+ ['calendar', 'freebusy', '--from=A', '--to=B'],
212
+ { account: undefined },
213
+ );
214
+ });
215
+
216
+ it('passes calendarIds and --all when provided', async () => {
217
+ await handlers.get('gog_calendar_freebusy')!({
218
+ from: 'A', to: 'B', calendarIds: 'primary,team@x.com', all: true,
219
+ });
220
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
221
+ ['calendar', 'freebusy', 'primary,team@x.com', '--from=A', '--to=B', '--all'],
222
+ { account: undefined },
223
+ );
224
+ });
225
+
226
+ it('omits --all when false', async () => {
227
+ await handlers.get('gog_calendar_freebusy')!({ from: 'A', to: 'B', all: false });
228
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
229
+ ['calendar', 'freebusy', '--from=A', '--to=B'],
230
+ { account: undefined },
231
+ );
232
+ });
233
+ });
234
+
235
+ describe('gog_calendar_colors', () => {
236
+ it('calls runOrDiagnose with the colors subcommand', async () => {
237
+ await handlers.get('gog_calendar_colors')!({});
238
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'colors'], { account: undefined });
239
+ });
240
+ });
241
+
242
+ describe('gog_calendar_acl', () => {
243
+ it('calls runOrDiagnose with calendarId only', async () => {
244
+ await handlers.get('gog_calendar_acl')!({ calendarId: 'primary' });
245
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'acl', 'primary'], { account: undefined });
246
+ });
247
+
248
+ it('passes pagination flags', async () => {
249
+ await handlers.get('gog_calendar_acl')!({ calendarId: 'primary', max: 25, page: 'tok', all: true });
250
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
251
+ ['calendar', 'acl', 'primary', '--max=25', '--page=tok', '--all'],
252
+ { account: undefined },
253
+ );
254
+ });
255
+
256
+ it('omits --all when false', async () => {
257
+ await handlers.get('gog_calendar_acl')!({ calendarId: 'primary', all: false });
258
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(['calendar', 'acl', 'primary'], { account: undefined });
259
+ });
260
+ });
261
+
262
+ describe('gog_calendar_move', () => {
263
+ it('calls runOrDiagnose with the three positionals', async () => {
264
+ await handlers.get('gog_calendar_move')!({
265
+ calendarId: 'primary', eventId: 'ev1', destinationCalendarId: 'team@x.com',
266
+ });
267
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
268
+ ['calendar', 'move', 'primary', 'ev1', 'team@x.com'],
269
+ { account: undefined },
270
+ );
271
+ });
272
+
273
+ it('passes --send-updates when provided', async () => {
274
+ await handlers.get('gog_calendar_move')!({
275
+ calendarId: 'primary', eventId: 'ev1', destinationCalendarId: 'team@x.com',
276
+ sendUpdates: 'all',
277
+ });
278
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
279
+ ['calendar', 'move', 'primary', 'ev1', 'team@x.com', '--send-updates=all'],
280
+ { account: undefined },
281
+ );
282
+ });
283
+ });
284
+
285
+ describe('gog_calendar_out_of_office', () => {
286
+ it('calls runOrDiagnose with required from/to only', async () => {
287
+ await handlers.get('gog_calendar_out_of_office')!({ from: '2026-06-01', to: '2026-06-05' });
288
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
289
+ ['calendar', 'out-of-office', '--from=2026-06-01', '--to=2026-06-05'],
290
+ { account: undefined },
291
+ );
292
+ });
293
+
294
+ it('passes calendarId and all optional flags when provided', async () => {
295
+ await handlers.get('gog_calendar_out_of_office')!({
296
+ from: '2026-06-01', to: '2026-06-05',
297
+ calendarId: 'primary',
298
+ summary: 'Vacation',
299
+ autoDecline: 'new',
300
+ declineMessage: 'Away',
301
+ allDay: true,
302
+ });
303
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
304
+ [
305
+ 'calendar', 'out-of-office', 'primary',
306
+ '--from=2026-06-01', '--to=2026-06-05',
307
+ '--summary=Vacation', '--auto-decline=new',
308
+ '--decline-message=Away', '--all-day',
309
+ ],
310
+ { account: undefined },
311
+ );
312
+ });
313
+
314
+ it('omits --all-day when false', async () => {
315
+ await handlers.get('gog_calendar_out_of_office')!({ from: '2026-06-01', to: '2026-06-05', allDay: false });
316
+ expect(lib.runOrDiagnose).toHaveBeenCalledWith(
317
+ ['calendar', 'out-of-office', '--from=2026-06-01', '--to=2026-06-05'],
318
+ { account: undefined },
319
+ );
320
+ });
321
+ });
322
+
146
323
  describe('gog_meet_participants', () => {
147
324
  it('calls runOrDiagnose with meetingCode', async () => {
148
325
  await handlers.get('gog_meet_participants')!({ meetingCode: 'abc-defg-hij' });