@mulmoclaude/google-plugin 0.3.0 → 0.3.3

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
@@ -10,6 +10,10 @@ export declare const GoogleArgs: z.ZodDiscriminatedUnion<[z.ZodObject<{
10
10
  calendarId: z.ZodOptional<z.ZodString>;
11
11
  timeMin: z.ZodOptional<z.ZodString>;
12
12
  maxResults: z.ZodOptional<z.ZodNumber>;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ kind: z.ZodLiteral<"calendarSync">;
15
+ calendarId: z.ZodOptional<z.ZodString>;
16
+ fullResync: z.ZodOptional<z.ZodBoolean>;
13
17
  }, z.core.$strip>, z.ZodObject<{
14
18
  kind: z.ZodLiteral<"calendarCreateEvent">;
15
19
  summary: z.ZodString;
@@ -22,6 +22,10 @@ export declare const TOOL_DEFINITION: {
22
22
  type: string;
23
23
  description: string;
24
24
  };
25
+ fullResync: {
26
+ type: string;
27
+ description: string;
28
+ };
25
29
  maxResults: {
26
30
  type: string;
27
31
  description: string;
package/dist/index.d.ts CHANGED
@@ -25,6 +25,10 @@ declare const _default: (runtime: import('gui-chat-protocol').PluginRuntime) =>
25
25
  type: string;
26
26
  description: string;
27
27
  };
28
+ fullResync: {
29
+ type: string;
30
+ description: string;
31
+ };
28
32
  maxResults: {
29
33
  type: string;
30
34
  description: string;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DEFAULT_LIST_MAX_RESULTS, MAX_LIST_RESULTS, clientSecretPresence, completeTask, createCalendarEvent, createDriveFile, createTask, getCalendarColors, getGoogleAccessToken, isIsoDateTimeWithOffset, listCalendarEvents, listCalendars, listDriveFiles, listTaskLists, listTasks, loadGoogleTokens, readDriveFile } from "@mulmoclaude/core/google";
1
+ import { DEFAULT_LIST_MAX_RESULTS, MAX_LIST_RESULTS, clearCalendarSyncToken, clientSecretPresence, completeTask, createCalendarEvent, createDriveFile, createTask, getCalendarColors, getGoogleAccessToken, isIsoDateTimeWithOffset, listCalendarEvents, listCalendars, listDriveFiles, listTaskLists, listTasks, loadCalendarSyncToken, loadGoogleTokens, readDriveFile, saveCalendarSyncToken, syncCalendarEvents } from "@mulmoclaude/core/google";
2
2
  //#region ../../../node_modules/gui-chat-protocol/dist/index.js
3
3
  function definePlugin(setup) {
4
4
  return setup;
@@ -4128,6 +4128,11 @@ var GoogleArgs = discriminatedUnion("kind", [
4128
4128
  timeMin: IsoDateTimeWithOffset.optional(),
4129
4129
  maxResults: MaxResults
4130
4130
  }),
4131
+ object({
4132
+ kind: literal("calendarSync"),
4133
+ calendarId: OptionalNonEmpty,
4134
+ fullResync: boolean().optional()
4135
+ }),
4131
4136
  object({
4132
4137
  kind: literal("calendarCreateEvent"),
4133
4138
  summary: NonEmpty,
@@ -4177,7 +4182,7 @@ var TOOL_DEFINITION = {
4177
4182
  type: "function",
4178
4183
  name: "google",
4179
4184
  prompt: "The user's Google account is linked LOCALLY on this machine — the refresh token lives in ~/.config/mulmo/ and never reaches any cloud. 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.",
4180
- 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 - `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\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 - `tasksComplete`: mark a task done. Requires `taskId` (from `tasksList`); optional `taskListId`.\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.",
4185
+ 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\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 - `tasksComplete`: mark a task done. Requires `taskId` (from `tasksList`); optional `taskListId`.\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.",
4181
4186
  parameters: {
4182
4187
  type: "object",
4183
4188
  properties: {
@@ -4188,6 +4193,7 @@ var TOOL_DEFINITION = {
4188
4193
  "calendarListCalendars",
4189
4194
  "calendarColors",
4190
4195
  "calendarListEvents",
4196
+ "calendarSync",
4191
4197
  "calendarCreateEvent",
4192
4198
  "taskListsList",
4193
4199
  "tasksList",
@@ -4210,6 +4216,10 @@ var TOOL_DEFINITION = {
4210
4216
  type: "string",
4211
4217
  description: "calendarListEvents: lower bound, ISO 8601 with timezone offset (default: now)"
4212
4218
  },
4219
+ fullResync: {
4220
+ type: "boolean",
4221
+ description: "calendarSync: discard the stored sync token and re-walk the whole calendar (default false)"
4222
+ },
4213
4223
  maxResults: {
4214
4224
  type: "number",
4215
4225
  description: "list kinds: max items to return, 1-50 (default 10)"
@@ -4277,6 +4287,38 @@ var TOOL_DEFINITION = {
4277
4287
  //#endregion
4278
4288
  //#region src/index.ts
4279
4289
  var LINK_GUIDANCE = "Ask the user to link their Google account in this app's settings, then retry.";
4290
+ var SYNC_SAMPLE_LIMIT = 20;
4291
+ var summarizeSync = (result, incremental) => {
4292
+ const active = result.events.filter((event) => event.status !== "cancelled");
4293
+ const cancelled = result.events.length - active.length;
4294
+ return {
4295
+ ok: true,
4296
+ incremental,
4297
+ changed: active.length,
4298
+ cancelled,
4299
+ events: active.slice(0, SYNC_SAMPLE_LIMIT),
4300
+ truncated: active.length > SYNC_SAMPLE_LIMIT
4301
+ };
4302
+ };
4303
+ async function restartFullSync(accessToken, calendarId) {
4304
+ await clearCalendarSyncToken(calendarId);
4305
+ return await syncCalendarEvents(accessToken, { calendarId });
4306
+ }
4307
+ async function runCalendarSync(calendarId, fullResync) {
4308
+ const accessToken = await getGoogleAccessToken();
4309
+ if (fullResync) await clearCalendarSyncToken(calendarId);
4310
+ const storedToken = fullResync ? null : await loadCalendarSyncToken(calendarId);
4311
+ const first = await syncCalendarEvents(accessToken, {
4312
+ calendarId,
4313
+ syncToken: storedToken ?? void 0
4314
+ });
4315
+ const result = first.fullResyncRequired ? await restartFullSync(accessToken, calendarId) : first;
4316
+ if (result.nextSyncToken) await saveCalendarSyncToken(calendarId, result.nextSyncToken);
4317
+ return {
4318
+ ...summarizeSync(result, Boolean(storedToken) && !first.fullResyncRequired),
4319
+ expiredToken: first.fullResyncRequired
4320
+ };
4321
+ }
4280
4322
  var src_default = definePlugin(({ log }) => {
4281
4323
  const dispatch = async (args) => {
4282
4324
  switch (args.kind) {
@@ -4306,6 +4348,7 @@ var src_default = definePlugin(({ log }) => {
4306
4348
  maxResults: args.maxResults ?? DEFAULT_LIST_MAX_RESULTS
4307
4349
  })
4308
4350
  };
4351
+ case "calendarSync": return await runCalendarSync(args.calendarId, args.fullResync ?? false);
4309
4352
  case "calendarCreateEvent": {
4310
4353
  const event = await createCalendarEvent(await getGoogleAccessToken(), {
4311
4354
  summary: args.summary,