@mulmoclaude/google-plugin 1.1.0 → 1.2.1

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/args.d.ts CHANGED
@@ -59,6 +59,10 @@ export declare const GoogleArgs: z.ZodDiscriminatedUnion<[z.ZodObject<{
59
59
  kind: z.ZodLiteral<"tasksComplete">;
60
60
  taskId: z.ZodString;
61
61
  taskListId: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$strip>, z.ZodObject<{
63
+ kind: z.ZodLiteral<"tasksUncomplete">;
64
+ taskId: z.ZodString;
65
+ taskListId: z.ZodOptional<z.ZodString>;
62
66
  }, z.core.$strip>, z.ZodObject<{
63
67
  kind: z.ZodLiteral<"tasksDelete">;
64
68
  taskId: z.ZodString;
@@ -0,0 +1,14 @@
1
+ import { PluginRuntime } from 'gui-chat-protocol';
2
+ import { GoogleArgs } from '../args';
3
+ import type * as GoogleEngine from "@mulmoclaude/core/google";
4
+ /** The engine surface the router calls. Signatures are taken from
5
+ * `@mulmoclaude/core/google` itself, so a change there fails this file
6
+ * instead of drifting past a hand-written duplicate. */
7
+ export type GoogleApi = Pick<typeof GoogleEngine, "clearCalendarSyncToken" | "clientSecretPresence" | "completeTask" | "createCalendarEvent" | "createDriveFile" | "createTask" | "deleteCalendarEvent" | "deleteTask" | "getCalendarColors" | "getGoogleAccessToken" | "listCalendarEvents" | "listCalendars" | "listDriveFiles" | "listTaskLists" | "listTasks" | "loadCalendarSyncToken" | "loadGoogleTokens" | "readDriveFile" | "saveCalendarSyncToken" | "syncCalendarEvents" | "uncompleteTask" | "updateCalendarEvent" | "updateTask">;
8
+ export interface GoogleDispatchContext {
9
+ api: GoogleApi;
10
+ /** Narrowed to what the router actually writes, so a test stub stays small. */
11
+ log: Pick<PluginRuntime["log"], "info">;
12
+ }
13
+ export declare const SYNC_SAMPLE_LIMIT = 20;
14
+ export declare function executeGoogleDispatch(context: GoogleDispatchContext, args: GoogleArgs): Promise<unknown>;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { DEFAULT_LIST_MAX_RESULTS, MAX_LIST_RESULTS, clearCalendarSyncToken, clientSecretPresence, completeTask, createCalendarEvent, createDriveFile, createTask, deleteCalendarEvent, deleteTask, getCalendarColors, getGoogleAccessToken, isIsoDateTimeWithOffset, listCalendarEvents, listCalendars, listDriveFiles, listTaskLists, listTasks, loadCalendarSyncToken, loadGoogleTokens, readDriveFile, saveCalendarSyncToken, syncCalendarEvents, updateCalendarEvent, updateTask } from "@mulmoclaude/core/google";
1
+ import * as googleApi from "@mulmoclaude/core/google";
2
+ import { DEFAULT_LIST_MAX_RESULTS, MAX_LIST_RESULTS, isIsoDateTimeWithOffset } from "@mulmoclaude/core/google";
2
3
  //#region ../../../node_modules/gui-chat-protocol/dist/index.js
3
4
  /**
4
5
  * Identity function for type inference. Same philosophy as
@@ -4243,6 +4244,11 @@ var GoogleArgs = discriminatedUnion("kind", [
4243
4244
  taskId: NonEmpty,
4244
4245
  taskListId: OptionalNonEmpty
4245
4246
  }),
4247
+ object({
4248
+ kind: literal("tasksUncomplete"),
4249
+ taskId: NonEmpty,
4250
+ taskListId: OptionalNonEmpty
4251
+ }),
4246
4252
  object({
4247
4253
  kind: literal("tasksDelete"),
4248
4254
  taskId: NonEmpty,
@@ -4264,12 +4270,236 @@ var GoogleArgs = discriminatedUnion("kind", [
4264
4270
  })
4265
4271
  ]);
4266
4272
  //#endregion
4273
+ //#region src/core/dispatch.ts
4274
+ var LINK_GUIDANCE = "Ask the user to link their Google account in this app's settings, then retry.";
4275
+ var summarizeSync = (result, incremental) => {
4276
+ const active = result.events.filter((event) => event.status !== "cancelled");
4277
+ const cancelled = result.events.length - active.length;
4278
+ return {
4279
+ ok: true,
4280
+ incremental,
4281
+ changed: active.length,
4282
+ cancelled,
4283
+ events: active.slice(0, 20),
4284
+ truncated: active.length > 20
4285
+ };
4286
+ };
4287
+ async function restartFullSync(api, accessToken, calendarId) {
4288
+ await api.clearCalendarSyncToken(calendarId);
4289
+ return await api.syncCalendarEvents(accessToken, { calendarId });
4290
+ }
4291
+ async function runCalendarSync(api, calendarId, fullResync) {
4292
+ const accessToken = await api.getGoogleAccessToken();
4293
+ if (fullResync) await api.clearCalendarSyncToken(calendarId);
4294
+ const storedToken = fullResync ? null : await api.loadCalendarSyncToken(calendarId);
4295
+ const first = await api.syncCalendarEvents(accessToken, {
4296
+ calendarId,
4297
+ syncToken: storedToken ?? void 0
4298
+ });
4299
+ const result = first.fullResyncRequired ? await restartFullSync(api, accessToken, calendarId) : first;
4300
+ if (result.nextSyncToken) await api.saveCalendarSyncToken(calendarId, result.nextSyncToken);
4301
+ return {
4302
+ ...summarizeSync(result, Boolean(storedToken) && !first.fullResyncRequired),
4303
+ expiredToken: first.fullResyncRequired
4304
+ };
4305
+ }
4306
+ var status = async ({ api }) => {
4307
+ const [tokens, clientSecret] = await Promise.all([api.loadGoogleTokens(), api.clientSecretPresence()]);
4308
+ const linked = Boolean(tokens?.refresh_token);
4309
+ return {
4310
+ ok: true,
4311
+ linked,
4312
+ clientSecret,
4313
+ ...linked ? {} : { guidance: LINK_GUIDANCE }
4314
+ };
4315
+ };
4316
+ var calendarListCalendars = async ({ api }) => ({
4317
+ ok: true,
4318
+ calendars: await api.listCalendars(await api.getGoogleAccessToken())
4319
+ });
4320
+ var calendarColors = async ({ api }) => ({
4321
+ ok: true,
4322
+ colors: await api.getCalendarColors(await api.getGoogleAccessToken())
4323
+ });
4324
+ var calendarListEvents = async ({ api }, args) => {
4325
+ return {
4326
+ ok: true,
4327
+ events: await api.listCalendarEvents(await api.getGoogleAccessToken(), {
4328
+ calendarId: args.calendarId,
4329
+ timeMin: args.timeMin,
4330
+ maxResults: args.maxResults ?? DEFAULT_LIST_MAX_RESULTS
4331
+ })
4332
+ };
4333
+ };
4334
+ var calendarSync = async ({ api }, args) => await runCalendarSync(api, args.calendarId, args.fullResync ?? false);
4335
+ var calendarCreateEvent = async ({ api, log }, args) => {
4336
+ const event = await api.createCalendarEvent(await api.getGoogleAccessToken(), {
4337
+ summary: args.summary,
4338
+ startDateTime: args.start,
4339
+ endDateTime: args.end,
4340
+ description: args.description,
4341
+ calendarId: args.calendarId,
4342
+ colorId: args.colorId
4343
+ });
4344
+ log.info("calendar event created", { id: event.id });
4345
+ return {
4346
+ ok: true,
4347
+ event
4348
+ };
4349
+ };
4350
+ var calendarUpdateEvent = async ({ api, log }, args) => {
4351
+ const event = await api.updateCalendarEvent(await api.getGoogleAccessToken(), {
4352
+ eventId: args.eventId,
4353
+ summary: args.summary,
4354
+ startDateTime: args.start,
4355
+ endDateTime: args.end,
4356
+ description: args.description,
4357
+ calendarId: args.calendarId,
4358
+ colorId: args.colorId
4359
+ });
4360
+ log.info("calendar event updated", { id: event.id });
4361
+ return {
4362
+ ok: true,
4363
+ event
4364
+ };
4365
+ };
4366
+ var calendarDeleteEvent = async ({ api, log }, args) => {
4367
+ await api.deleteCalendarEvent(await api.getGoogleAccessToken(), {
4368
+ eventId: args.eventId,
4369
+ calendarId: args.calendarId
4370
+ });
4371
+ log.info("calendar event deleted", { id: args.eventId });
4372
+ return {
4373
+ ok: true,
4374
+ deleted: args.eventId
4375
+ };
4376
+ };
4377
+ var taskListsList = async ({ api }) => ({
4378
+ ok: true,
4379
+ taskLists: await api.listTaskLists(await api.getGoogleAccessToken())
4380
+ });
4381
+ var tasksList = async ({ api }, args) => {
4382
+ return {
4383
+ ok: true,
4384
+ tasks: await api.listTasks(await api.getGoogleAccessToken(), {
4385
+ taskListId: args.taskListId,
4386
+ maxResults: args.maxResults ?? DEFAULT_LIST_MAX_RESULTS,
4387
+ showCompleted: args.showCompleted
4388
+ })
4389
+ };
4390
+ };
4391
+ var tasksCreate = async ({ api, log }, args) => {
4392
+ const task = await api.createTask(await api.getGoogleAccessToken(), {
4393
+ title: args.title,
4394
+ notes: args.notes,
4395
+ due: args.due,
4396
+ taskListId: args.taskListId
4397
+ });
4398
+ log.info("task created", { id: task.id });
4399
+ return {
4400
+ ok: true,
4401
+ task
4402
+ };
4403
+ };
4404
+ var tasksUpdate = async ({ api, log }, args) => {
4405
+ const task = await api.updateTask(await api.getGoogleAccessToken(), {
4406
+ taskId: args.taskId,
4407
+ title: args.title,
4408
+ notes: args.notes,
4409
+ due: args.due,
4410
+ taskListId: args.taskListId
4411
+ });
4412
+ log.info("task updated", { id: task.id });
4413
+ return {
4414
+ ok: true,
4415
+ task
4416
+ };
4417
+ };
4418
+ var tasksComplete = async ({ api }, args) => {
4419
+ return {
4420
+ ok: true,
4421
+ task: await api.completeTask(await api.getGoogleAccessToken(), {
4422
+ taskId: args.taskId,
4423
+ taskListId: args.taskListId
4424
+ })
4425
+ };
4426
+ };
4427
+ var tasksUncomplete = async ({ api }, args) => {
4428
+ return {
4429
+ ok: true,
4430
+ task: await api.uncompleteTask(await api.getGoogleAccessToken(), {
4431
+ taskId: args.taskId,
4432
+ taskListId: args.taskListId
4433
+ })
4434
+ };
4435
+ };
4436
+ var tasksDelete = async ({ api, log }, args) => {
4437
+ await api.deleteTask(await api.getGoogleAccessToken(), {
4438
+ taskId: args.taskId,
4439
+ taskListId: args.taskListId
4440
+ });
4441
+ log.info("task deleted", { id: args.taskId });
4442
+ return {
4443
+ ok: true,
4444
+ deleted: args.taskId
4445
+ };
4446
+ };
4447
+ var driveList = async ({ api }, args) => {
4448
+ return {
4449
+ ok: true,
4450
+ files: await api.listDriveFiles(await api.getGoogleAccessToken(), { maxResults: args.maxResults ?? DEFAULT_LIST_MAX_RESULTS })
4451
+ };
4452
+ };
4453
+ var driveCreate = async ({ api, log }, args) => {
4454
+ const file = await api.createDriveFile(await api.getGoogleAccessToken(), {
4455
+ name: args.name,
4456
+ content: args.content,
4457
+ mimeType: args.mimeType
4458
+ });
4459
+ log.info("drive file created", { id: file.id });
4460
+ return {
4461
+ ok: true,
4462
+ file
4463
+ };
4464
+ };
4465
+ var driveRead = async ({ api }, args) => {
4466
+ const { file, content } = await api.readDriveFile(await api.getGoogleAccessToken(), { fileId: args.fileId });
4467
+ return {
4468
+ ok: true,
4469
+ file,
4470
+ content
4471
+ };
4472
+ };
4473
+ async function executeGoogleDispatch(context, args) {
4474
+ switch (args.kind) {
4475
+ case "status": return await status(context);
4476
+ case "calendarListCalendars": return await calendarListCalendars(context);
4477
+ case "calendarColors": return await calendarColors(context);
4478
+ case "calendarListEvents": return await calendarListEvents(context, args);
4479
+ case "calendarSync": return await calendarSync(context, args);
4480
+ case "calendarCreateEvent": return await calendarCreateEvent(context, args);
4481
+ case "calendarUpdateEvent": return await calendarUpdateEvent(context, args);
4482
+ case "calendarDeleteEvent": return await calendarDeleteEvent(context, args);
4483
+ case "taskListsList": return await taskListsList(context);
4484
+ case "tasksList": return await tasksList(context, args);
4485
+ case "tasksCreate": return await tasksCreate(context, args);
4486
+ case "tasksUpdate": return await tasksUpdate(context, args);
4487
+ case "tasksComplete": return await tasksComplete(context, args);
4488
+ case "tasksUncomplete": return await tasksUncomplete(context, args);
4489
+ case "tasksDelete": return await tasksDelete(context, args);
4490
+ case "driveList": return await driveList(context, args);
4491
+ case "driveCreate": return await driveCreate(context, args);
4492
+ case "driveRead": return await driveRead(context, args);
4493
+ default: throw new Error(`unknown kind: ${JSON.stringify(args)}`);
4494
+ }
4495
+ }
4496
+ //#endregion
4267
4497
  //#region src/definition.ts
4268
4498
  var TOOL_DEFINITION = {
4269
4499
  type: "function",
4270
4500
  name: "google",
4271
4501
  prompt: "The user's Google account is linked LOCALLY on this machine — the refresh token is stored in ~/.config/mulmo/ and goes only to Google to mint access tokens, never to claude.ai or any other service. This is independent of claude.ai Google connectors; the tool works without them. If a call fails with 'Google account not linked', ask the user to link their Google account in this app's settings, then retry the original call.",
4272
- description: "Operate the user's Google services through the locally linked Google account: Calendar, Tasks, and Drive. Supported kinds:\n - `status`: report whether the Google account is linked on this machine — call this first when unsure.\n\nCalendar (events default to the primary calendar; pass `calendarId` — from `calendarListCalendars` — to target another):\n - `calendarListCalendars`: list the calendars the user has added/subscribed to (`id`, `summary`, `primary`, `backgroundColor`/`foregroundColor` hex, `colorId`, `accessRole`). Call this to work with a non-primary calendar.\n - `calendarColors`: palettes that map an event/calendar `colorId` to hex — `event` for per-event colours, `calendar` for calendar colours.\n - `calendarListEvents`: list upcoming events (each carries `colorId`, empty when it inherits the calendar colour). Optional `calendarId`, `timeMin` (ISO 8601 date-time with timezone offset; default now), `maxResults` (1-50, default 10).\n - `calendarSync`: fetch only what CHANGED since the last sync of this calendar, using a stored sync token. Use this for repeated/periodic syncing — it does not re-fetch the whole calendar, so it stays cheap. The FIRST call (or after `fullResync: true`) walks the entire calendar to establish the token. Returns counts (`changed`, `cancelled`) plus a capped `events` sample — never the full list, so it will not flood the conversation; `truncated: true` means more changed than are shown. Deletions are reported as the `cancelled` count. Optional `calendarId`, `fullResync` (discard the stored token and start over).\n - `calendarCreateEvent`: create an event. Requires `summary`, `start`, `end` — ISO 8601 date-times WITH a timezone offset (e.g. 2026-07-17T09:00:00+09:00); optional `description`, `calendarId`, `colorId` (event palette id \"1\"-\"11\").\n - `calendarUpdateEvent`: edit an existing event. Requires `eventId` (from `calendarListEvents` / `calendarSync`) plus AT LEAST ONE of `summary`, `start`, `end`, `description`, `colorId`; fields you omit keep their current value, and `description: \"\"` clears the body. Optional `calendarId`. Moving only one end of the event still has to leave start before end, or Calendar rejects it.\n - `calendarDeleteEvent`: delete an event. Requires `eventId`; optional `calendarId`. This removes it for every attendee and cannot be undone — confirm with the user before calling. For a recurring event, an instance id (as returned by the list kinds) deletes that single occurrence.\n\nTasks:\n - `taskListsList`: list the user's task lists (`id`, `title`). Only needed when the user means a list other than their default one.\n - `tasksList`: list tasks. Optional `taskListId` (default: the user's default list), `maxResults` (1-50, default 10), `showCompleted` (default false).\n - `tasksCreate`: add a task. Requires `title`; optional `notes`, `due` (ISO 8601 with offset — Google keeps the DATE only, so do not promise a time of day), `taskListId`.\n - `tasksUpdate`: edit a task. Requires `taskId` (from `tasksList`) plus AT LEAST ONE of `title`, `notes`, `due`; omitted fields keep their value and `notes: \"\"` clears them. Use `tasksComplete` to mark it done — this kind does not change status. Optional `taskListId`.\n - `tasksComplete`: mark a task done. Requires `taskId` (from `tasksList`); optional `taskListId`.\n - `tasksDelete`: delete a task. Requires `taskId`; optional `taskListId`. Cannot be undone — confirm with the user before calling.\n\nDrive — IMPORTANT: this app can only see files IT created, never the user's wider Drive. Never claim you searched their whole Drive:\n - `driveList`: list files this app created. Optional `maxResults` (1-50, default 10).\n - `driveCreate`: create a text file. Requires `name` and `content`; optional `mimeType` (default text/plain).\n - `driveRead`: read one of this app's files. Requires `fileId` (from `driveList` or `driveCreate`). Text files only.",
4502
+ description: "Operate the user's Google services through the locally linked Google account: Calendar, Tasks, and Drive. Supported kinds:\n - `status`: report whether the Google account is linked on this machine — call this first when unsure.\n\nCalendar (events default to the primary calendar; pass `calendarId` — from `calendarListCalendars` — to target another):\n - `calendarListCalendars`: list the calendars the user has added/subscribed to (`id`, `summary`, `primary`, `backgroundColor`/`foregroundColor` hex, `colorId`, `accessRole`). Call this to work with a non-primary calendar.\n - `calendarColors`: palettes that map an event/calendar `colorId` to hex — `event` for per-event colours, `calendar` for calendar colours.\n - `calendarListEvents`: list upcoming events (each carries `colorId`, empty when it inherits the calendar colour). Optional `calendarId`, `timeMin` (ISO 8601 date-time with timezone offset; default now), `maxResults` (1-50, default 10).\n - `calendarSync`: fetch only what CHANGED since the last sync of this calendar, using a stored sync token. Use this for repeated/periodic syncing — it does not re-fetch the whole calendar, so it stays cheap. The FIRST call (or after `fullResync: true`) walks the entire calendar to establish the token. Returns counts (`changed`, `cancelled`) plus a capped `events` sample — never the full list, so it will not flood the conversation; `truncated: true` means more changed than are shown. Deletions are reported as the `cancelled` count. Optional `calendarId`, `fullResync` (discard the stored token and start over).\n - `calendarCreateEvent`: create an event. Requires `summary`, `start`, `end` — ISO 8601 date-times WITH a timezone offset (e.g. 2026-07-17T09:00:00+09:00); optional `description`, `calendarId`, `colorId` (event palette id \"1\"-\"11\").\n - `calendarUpdateEvent`: edit an existing event. Requires `eventId` (from `calendarListEvents` / `calendarSync`) plus AT LEAST ONE of `summary`, `start`, `end`, `description`, `colorId`; fields you omit keep their current value, and `description: \"\"` clears the body. Optional `calendarId`. Moving only one end of the event still has to leave start before end, or Calendar rejects it.\n - `calendarDeleteEvent`: delete an event. Requires `eventId`; optional `calendarId`. This removes it for every attendee and cannot be undone — confirm with the user before calling. For a recurring event, an instance id (as returned by the list kinds) deletes that single occurrence.\n\nTasks:\n - `taskListsList`: list the user's task lists (`id`, `title`). Only needed when the user means a list other than their default one.\n - `tasksList`: list tasks. Optional `taskListId` (default: the user's default list), `maxResults` (1-50, default 10), `showCompleted` (default false).\n - `tasksCreate`: add a task. Requires `title`; optional `notes`, `due` (ISO 8601 with offset — Google keeps the DATE only, so do not promise a time of day), `taskListId`.\n - `tasksUpdate`: edit a task. Requires `taskId` (from `tasksList`) plus AT LEAST ONE of `title`, `notes`, `due`; omitted fields keep their value and `notes: \"\"` clears them. Use `tasksComplete` / `tasksUncomplete` to change status — this kind does not. Optional `taskListId`.\n - `tasksComplete`: mark a task done. Requires `taskId` (from `tasksList`); optional `taskListId`.\n - `tasksUncomplete`: put a completed task back on the to-do list. Requires `taskId`; optional `taskListId`. Completed tasks are hidden from `tasksList` unless you pass `showCompleted: true`, so list with that first to find the id.\n - `tasksDelete`: delete a task. Requires `taskId`; optional `taskListId`. Cannot be undone — confirm with the user before calling.\n\nDrive — IMPORTANT: this app can only see files IT created, never the user's wider Drive. Never claim you searched their whole Drive:\n - `driveList`: list files this app created. Optional `maxResults` (1-50, default 10).\n - `driveCreate`: create a text file. Requires `name` and `content`; optional `mimeType` (default text/plain).\n - `driveRead`: read one of this app's files. Requires `fileId` (from `driveList` or `driveCreate`). Text files only.",
4273
4503
  parameters: {
4274
4504
  type: "object",
4275
4505
  properties: {
@@ -4289,6 +4519,7 @@ var TOOL_DEFINITION = {
4289
4519
  "tasksCreate",
4290
4520
  "tasksUpdate",
4291
4521
  "tasksComplete",
4522
+ "tasksUncomplete",
4292
4523
  "tasksDelete",
4293
4524
  "driveList",
4294
4525
  "driveCreate",
@@ -4357,7 +4588,7 @@ var TOOL_DEFINITION = {
4357
4588
  },
4358
4589
  taskId: {
4359
4590
  type: "string",
4360
- description: "tasksUpdate / tasksComplete / tasksDelete: id of the task, from tasksList"
4591
+ description: "tasksUpdate / tasksComplete / tasksUncomplete / tasksDelete: id of the task, from tasksList"
4361
4592
  },
4362
4593
  name: {
4363
4594
  type: "string",
@@ -4381,200 +4612,15 @@ var TOOL_DEFINITION = {
4381
4612
  };
4382
4613
  //#endregion
4383
4614
  //#region src/index.ts
4384
- var LINK_GUIDANCE = "Ask the user to link their Google account in this app's settings, then retry.";
4385
- var SYNC_SAMPLE_LIMIT = 20;
4386
- var summarizeSync = (result, incremental) => {
4387
- const active = result.events.filter((event) => event.status !== "cancelled");
4388
- const cancelled = result.events.length - active.length;
4389
- return {
4390
- ok: true,
4391
- incremental,
4392
- changed: active.length,
4393
- cancelled,
4394
- events: active.slice(0, SYNC_SAMPLE_LIMIT),
4395
- truncated: active.length > SYNC_SAMPLE_LIMIT
4396
- };
4397
- };
4398
- async function restartFullSync(accessToken, calendarId) {
4399
- await clearCalendarSyncToken(calendarId);
4400
- return await syncCalendarEvents(accessToken, { calendarId });
4401
- }
4402
- async function runCalendarSync(calendarId, fullResync) {
4403
- const accessToken = await getGoogleAccessToken();
4404
- if (fullResync) await clearCalendarSyncToken(calendarId);
4405
- const storedToken = fullResync ? null : await loadCalendarSyncToken(calendarId);
4406
- const first = await syncCalendarEvents(accessToken, {
4407
- calendarId,
4408
- syncToken: storedToken ?? void 0
4409
- });
4410
- const result = first.fullResyncRequired ? await restartFullSync(accessToken, calendarId) : first;
4411
- if (result.nextSyncToken) await saveCalendarSyncToken(calendarId, result.nextSyncToken);
4412
- return {
4413
- ...summarizeSync(result, Boolean(storedToken) && !first.fullResyncRequired),
4414
- expiredToken: first.fullResyncRequired
4415
- };
4416
- }
4417
- var src_default = definePlugin(({ log }) => {
4418
- const dispatch = async (args) => {
4419
- switch (args.kind) {
4420
- case "status": {
4421
- const [tokens, clientSecret] = await Promise.all([loadGoogleTokens(), clientSecretPresence()]);
4422
- const linked = Boolean(tokens?.refresh_token);
4423
- return {
4424
- ok: true,
4425
- linked,
4426
- clientSecret,
4427
- ...linked ? {} : { guidance: LINK_GUIDANCE }
4428
- };
4429
- }
4430
- case "calendarListCalendars": return {
4431
- ok: true,
4432
- calendars: await listCalendars(await getGoogleAccessToken())
4433
- };
4434
- case "calendarColors": return {
4435
- ok: true,
4436
- colors: await getCalendarColors(await getGoogleAccessToken())
4437
- };
4438
- case "calendarListEvents": return {
4439
- ok: true,
4440
- events: await listCalendarEvents(await getGoogleAccessToken(), {
4441
- calendarId: args.calendarId,
4442
- timeMin: args.timeMin,
4443
- maxResults: args.maxResults ?? DEFAULT_LIST_MAX_RESULTS
4444
- })
4445
- };
4446
- case "calendarSync": return await runCalendarSync(args.calendarId, args.fullResync ?? false);
4447
- case "calendarCreateEvent": {
4448
- const event = await createCalendarEvent(await getGoogleAccessToken(), {
4449
- summary: args.summary,
4450
- startDateTime: args.start,
4451
- endDateTime: args.end,
4452
- description: args.description,
4453
- calendarId: args.calendarId,
4454
- colorId: args.colorId
4455
- });
4456
- log.info("calendar event created", { id: event.id });
4457
- return {
4458
- ok: true,
4459
- event
4460
- };
4461
- }
4462
- case "calendarUpdateEvent": {
4463
- const event = await updateCalendarEvent(await getGoogleAccessToken(), {
4464
- eventId: args.eventId,
4465
- summary: args.summary,
4466
- startDateTime: args.start,
4467
- endDateTime: args.end,
4468
- description: args.description,
4469
- calendarId: args.calendarId,
4470
- colorId: args.colorId
4471
- });
4472
- log.info("calendar event updated", { id: event.id });
4473
- return {
4474
- ok: true,
4475
- event
4476
- };
4477
- }
4478
- case "calendarDeleteEvent":
4479
- await deleteCalendarEvent(await getGoogleAccessToken(), {
4480
- eventId: args.eventId,
4481
- calendarId: args.calendarId
4482
- });
4483
- log.info("calendar event deleted", { id: args.eventId });
4484
- return {
4485
- ok: true,
4486
- deleted: args.eventId
4487
- };
4488
- case "taskListsList": return {
4489
- ok: true,
4490
- taskLists: await listTaskLists(await getGoogleAccessToken())
4491
- };
4492
- case "tasksList": return {
4493
- ok: true,
4494
- tasks: await listTasks(await getGoogleAccessToken(), {
4495
- taskListId: args.taskListId,
4496
- maxResults: args.maxResults ?? DEFAULT_LIST_MAX_RESULTS,
4497
- showCompleted: args.showCompleted
4498
- })
4499
- };
4500
- case "tasksCreate": {
4501
- const task = await createTask(await getGoogleAccessToken(), {
4502
- title: args.title,
4503
- notes: args.notes,
4504
- due: args.due,
4505
- taskListId: args.taskListId
4506
- });
4507
- log.info("task created", { id: task.id });
4508
- return {
4509
- ok: true,
4510
- task
4511
- };
4512
- }
4513
- case "tasksUpdate": {
4514
- const task = await updateTask(await getGoogleAccessToken(), {
4515
- taskId: args.taskId,
4516
- title: args.title,
4517
- notes: args.notes,
4518
- due: args.due,
4519
- taskListId: args.taskListId
4520
- });
4521
- log.info("task updated", { id: task.id });
4522
- return {
4523
- ok: true,
4524
- task
4525
- };
4526
- }
4527
- case "tasksComplete": return {
4528
- ok: true,
4529
- task: await completeTask(await getGoogleAccessToken(), {
4530
- taskId: args.taskId,
4531
- taskListId: args.taskListId
4532
- })
4533
- };
4534
- case "tasksDelete":
4535
- await deleteTask(await getGoogleAccessToken(), {
4536
- taskId: args.taskId,
4537
- taskListId: args.taskListId
4538
- });
4539
- log.info("task deleted", { id: args.taskId });
4540
- return {
4541
- ok: true,
4542
- deleted: args.taskId
4543
- };
4544
- case "driveList": return {
4545
- ok: true,
4546
- files: await listDriveFiles(await getGoogleAccessToken(), { maxResults: args.maxResults ?? DEFAULT_LIST_MAX_RESULTS })
4547
- };
4548
- case "driveCreate": {
4549
- const file = await createDriveFile(await getGoogleAccessToken(), {
4550
- name: args.name,
4551
- content: args.content,
4552
- mimeType: args.mimeType
4553
- });
4554
- log.info("drive file created", { id: file.id });
4555
- return {
4556
- ok: true,
4557
- file
4558
- };
4559
- }
4560
- case "driveRead": {
4561
- const { file, content } = await readDriveFile(await getGoogleAccessToken(), { fileId: args.fileId });
4562
- return {
4563
- ok: true,
4564
- file,
4565
- content
4566
- };
4567
- }
4568
- default: throw new Error(`unknown kind: ${JSON.stringify(args)}`);
4569
- }
4570
- };
4571
- return {
4572
- TOOL_DEFINITION,
4573
- async google(rawArgs) {
4574
- return await dispatch(GoogleArgs.parse(rawArgs));
4575
- }
4576
- };
4577
- });
4615
+ var src_default = definePlugin(({ log }) => ({
4616
+ TOOL_DEFINITION,
4617
+ async google(rawArgs) {
4618
+ return await executeGoogleDispatch({
4619
+ api: googleApi,
4620
+ log
4621
+ }, GoogleArgs.parse(rawArgs));
4622
+ }
4623
+ }));
4578
4624
  //#endregion
4579
4625
  export { TOOL_DEFINITION, src_default as default };
4580
4626