@chibitek/chibi 0.1.173 → 0.1.174

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.
Files changed (70) hide show
  1. package/dist/assets/{abnfDiagram-O67JEVCF-DaA9WpZw.js → abnfDiagram-O67JEVCF-BVDndX1g.js} +1 -1
  2. package/dist/assets/{arc-DJ4Kdvv6.js → arc-WduS6wYB.js} +1 -1
  3. package/dist/assets/{architectureDiagram-NJMV4G6O-B975BUTv.js → architectureDiagram-NJMV4G6O-CYK9LkCf.js} +1 -1
  4. package/dist/assets/{blockDiagram-BEXU5L5S-CXOOfLy7.js → blockDiagram-BEXU5L5S-BMj-aPW9.js} +1 -1
  5. package/dist/assets/{c4Diagram-YGBWAQC7-CorqQ94E.js → c4Diagram-YGBWAQC7-cXYIStgL.js} +1 -1
  6. package/dist/assets/channel-TratrwmM.js +1 -0
  7. package/dist/assets/{chunk-2Q5K7J3B-CPFHpKez.js → chunk-2Q5K7J3B-CZ_nCppA.js} +1 -1
  8. package/dist/assets/{chunk-3FUC2YCW-CrzBuB3A.js → chunk-3FUC2YCW-C3wRAbtM.js} +2 -2
  9. package/dist/assets/{chunk-5VM5RSS4-DXJTBdvO.js → chunk-5VM5RSS4-CMvgOXJP.js} +1 -1
  10. package/dist/assets/{chunk-GTNCS2PH-B0TxALG4.js → chunk-GTNCS2PH-9wBuLQzU.js} +1 -1
  11. package/dist/assets/{chunk-GWA4HPMP-BL44uVOP.js → chunk-GWA4HPMP-BpJMmfAi.js} +1 -1
  12. package/dist/assets/{chunk-JWPE2WC7-CxSklH7P.js → chunk-JWPE2WC7-BnM06ABv.js} +1 -1
  13. package/dist/assets/{chunk-NETBCI7D-_Lb-D8AY.js → chunk-NETBCI7D-CjjiiXiT.js} +1 -1
  14. package/dist/assets/{chunk-WEXAMYUT-Dz5jp0xb.js → chunk-WEXAMYUT-D3heHHZs.js} +1 -1
  15. package/dist/assets/{chunk-XXDRQBXY-C-cd9N0r.js → chunk-XXDRQBXY-n_P41ZlM.js} +1 -1
  16. package/dist/assets/{classDiagram-v2-NBCMYWYE-DtQ1781-.js → classDiagram-v2-NBCMYWYE-Dz60Ek-6.js} +1 -1
  17. package/dist/assets/{cose-bilkent-JH36ORCC-CHzWXNdH.js → cose-bilkent-JH36ORCC-BCt6vBi9.js} +1 -1
  18. package/dist/assets/{cynefin-OW5HDTMX-lHbKcf1S.js → cynefin-OW5HDTMX-U0uq4EAQ.js} +1 -1
  19. package/dist/assets/{cynefinDiagram-VND7K2PF-BxY6MCKD.js → cynefinDiagram-VND7K2PF-CaQX0eUJ.js} +1 -1
  20. package/dist/assets/{dagre-6A5THRUB-C2SBw-Mo.js → dagre-6A5THRUB-DlCMESYH.js} +1 -1
  21. package/dist/assets/{diagram-22UHCM2B-BwIAlmAU.js → diagram-22UHCM2B-Cl1xmlTD.js} +1 -1
  22. package/dist/assets/{diagram-3UASUU5V-i6fBkckD.js → diagram-3UASUU5V-Cus3CPg7.js} +1 -1
  23. package/dist/assets/{diagram-ATOU4E4O-DwedCbB_.js → diagram-ATOU4E4O-i06rMvae.js} +1 -1
  24. package/dist/assets/{diagram-CDSNMT55-BISF-AQC.js → diagram-CDSNMT55-CUM5_heN.js} +1 -1
  25. package/dist/assets/{diagram-MLGK6HIB-ImgdRRxp.js → diagram-MLGK6HIB-B5NKRruo.js} +1 -1
  26. package/dist/assets/{diagram-MPIPVDR6-CxlAwPCS.js → diagram-MPIPVDR6-CAumAcGl.js} +1 -1
  27. package/dist/assets/{ebnfDiagram-ZINNZB2B-sVJkymKa.js → ebnfDiagram-ZINNZB2B-B19d7d8l.js} +1 -1
  28. package/dist/assets/{elk-276RUBZZ-DU1vyX4w.js → elk-276RUBZZ-NJEpfRWi.js} +1 -1
  29. package/dist/assets/{erDiagram-OPXOYQCR-CnCmL1Ve.js → erDiagram-OPXOYQCR-BExk6CHc.js} +1 -1
  30. package/dist/assets/{flowDiagram-KWPJA3E3-DME2uLJf.js → flowDiagram-KWPJA3E3-ClExQ_p0.js} +1 -1
  31. package/dist/assets/{ganttDiagram-FUAMR5RP-CJQNW9ts.js → ganttDiagram-FUAMR5RP-1MeM9sSl.js} +1 -1
  32. package/dist/assets/{gitGraphDiagram-X574FWY7-D88_Y9tg.js → gitGraphDiagram-X574FWY7-Tw9Dudpa.js} +1 -1
  33. package/dist/assets/{index-U9LN4GhF.js → index-KYHldywn.js} +3 -3
  34. package/dist/assets/{index-ChmZZe7i.js → index-qsorLr2x.js} +1 -1
  35. package/dist/assets/{infoDiagram-VRGFBTTK-CxWEf3NI.js → infoDiagram-VRGFBTTK-ChU2tjvl.js} +1 -1
  36. package/dist/assets/{ishikawaDiagram-OU5B5YK6-B_YoNVjF.js → ishikawaDiagram-OU5B5YK6-BeTbrX2Q.js} +1 -1
  37. package/dist/assets/{journeyDiagram-ZHPQQLJL-ZYuBE2Bm.js → journeyDiagram-ZHPQQLJL-B7ijaWBD.js} +1 -1
  38. package/dist/assets/{kanban-definition-PNTS6WVX-jmY_M4Qf.js → kanban-definition-PNTS6WVX-JBmK2F1r.js} +1 -1
  39. package/dist/assets/{linear-kKUF6ayN.js → linear-B7FXe3Ue.js} +1 -1
  40. package/dist/assets/{mermaid.core-DC5051S_.js → mermaid.core-BPlfZpqv.js} +5 -5
  41. package/dist/assets/{mindmap-definition-NLK3R4M7-C5knfygJ.js → mindmap-definition-NLK3R4M7-CmT3S5QR.js} +1 -1
  42. package/dist/assets/{pegDiagram-GJSIUBJH-Ex6iedL2.js → pegDiagram-GJSIUBJH-CFFHIcdQ.js} +1 -1
  43. package/dist/assets/{pieDiagram-5QR66LMP-Dv38Ox0D.js → pieDiagram-5QR66LMP-yTiPmXRV.js} +1 -1
  44. package/dist/assets/{quadrantDiagram-O4NWA36T-CwOEor8N.js → quadrantDiagram-O4NWA36T-Cw8u7esm.js} +1 -1
  45. package/dist/assets/{railroadDiagram-XR7U4H2S-DVgqz5MR.js → railroadDiagram-XR7U4H2S-BfKggsOW.js} +1 -1
  46. package/dist/assets/{requirementDiagram-PLB6GJNP-BxiuYo52.js → requirementDiagram-PLB6GJNP-Cf3n79jF.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-IPEJSGJF--vq_1flP.js → sankeyDiagram-IPEJSGJF-B2NkSZig.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-PO4LG4MO-9hLpfPA6.js → sequenceDiagram-PO4LG4MO-BfFYiYK3.js} +1 -1
  49. package/dist/assets/{sizeCapture-INFHLROL-BeGMkj9s.js → sizeCapture-INFHLROL-CZ_2nC3f.js} +1 -1
  50. package/dist/assets/{stateDiagram-v2-GCMORJYK-BnNOMugb.js → stateDiagram-v2-GCMORJYK-B9jwzMXf.js} +1 -1
  51. package/dist/assets/{swimlanes-2SLR337P-C1YG6Jq-.js → swimlanes-2SLR337P-Bxhafu77.js} +1 -1
  52. package/dist/assets/swimlanesDiagram-TC7HE7FX-DWNGCaH3.js +8 -0
  53. package/dist/assets/{timeline-definition-EJHVYXUP-Co7OtwGA.js → timeline-definition-EJHVYXUP-Dle5SJls.js} +1 -1
  54. package/dist/assets/{usecaseDiagram-POWQR4AR-BYHFARv3.js → usecaseDiagram-POWQR4AR-CgRTu9EO.js} +1 -1
  55. package/dist/assets/{vennDiagram-UO4OBE2U-C-sdhL3h.js → vennDiagram-UO4OBE2U-D7m_1z6B.js} +1 -1
  56. package/dist/assets/{wardleyDiagram-VNRHLVJA-wf8ZNrmQ.js → wardleyDiagram-VNRHLVJA-7-TzmX4L.js} +1 -1
  57. package/dist/assets/{xychartDiagram-PMCCYNJV-BjRlkVGv.js → xychartDiagram-PMCCYNJV-BVXXdviS.js} +1 -1
  58. package/dist/index.html +1 -1
  59. package/dist-server/index.js +645 -327
  60. package/dist-server/openmausbot.js +2 -2
  61. package/dist-server/pair-cli.js +2 -2
  62. package/dist-server/server/dictation.js +8 -0
  63. package/dist-server/server/drivers/claude.js +4 -4
  64. package/dist-server/server/oauth-account-core.js +153 -0
  65. package/dist-server/server/oauth-account-tools.js +7 -348
  66. package/dist-server/server/oauth-calendar-tools.js +551 -0
  67. package/dist-server/shared/oauth-providers.js +2 -1
  68. package/package.json +1 -1
  69. package/dist/assets/channel-sBYHnjxz.js +0 -1
  70. package/dist/assets/swimlanesDiagram-TC7HE7FX-9DghUs7S.js +0 -8
@@ -7780,10 +7780,10 @@ var require_formats = __commonJS({
7780
7780
  function isLeapYear(year) {
7781
7781
  return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
7782
7782
  }
7783
- var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
7783
+ var DATE2 = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
7784
7784
  var DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
7785
7785
  function date5(str5) {
7786
- const matches2 = DATE.exec(str5);
7786
+ const matches2 = DATE2.exec(str5);
7787
7787
  if (!matches2)
7788
7788
  return false;
7789
7789
  const year = +matches2[1];
@@ -38281,8 +38281,8 @@ function autoCompactWindow(env) {
38281
38281
  var DEFAULT_AUTOCOMPACT_TOKENS = 2e5;
38282
38282
  var CLAUDE_FLAG_FLOORS = {
38283
38283
  "--strict-mcp-config": [1, 0, 60],
38284
- "--setting-sources": [1, 0, 122],
38285
- "--autocompact": [2, 1, 122],
38284
+ "--setting-sources": [1, 0, 125],
38285
+ "--autocompact": [2, 1, 221],
38286
38286
  // 2.1.267 is the first CLI that accepts it; below that the recorded prompt
38287
38287
  // simply is not refreshed, which is the pre-existing behaviour.
38288
38288
  "--system-prompt-snapshot": [2, 1, 267],
@@ -54342,8 +54342,8 @@ var McpHealthStore = class {
54342
54342
  const entry = this.entry(name2, spec);
54343
54343
  if (!entry) return void 0;
54344
54344
  const what = entry.kind === "crashed" ? "stopped working during a bot's turn" : "would not start";
54345
- const when = this.now() >= entry.retryAt ? "Atomic tries it again on the next turn." : `Atomic tries it again at ${formatTime(entry.retryAt)}.`;
54346
- return `This server ${what}, so bots are working without it for now. ${when} Check its command and settings if this keeps happening.`;
54345
+ const when2 = this.now() >= entry.retryAt ? "Atomic tries it again on the next turn." : `Atomic tries it again at ${formatTime(entry.retryAt)}.`;
54346
+ return `This server ${what}, so bots are working without it for now. ${when2} Check its command and settings if this keeps happening.`;
54347
54347
  }
54348
54348
  /** Why a server is left out of turns right now, or undefined when it mounts. */
54349
54349
  unavailableKind(name2, spec) {
@@ -92669,7 +92669,7 @@ Name: ${name2}`,
92669
92669
  }
92670
92670
  const nextRunAt = nextForOperation(operation, manager, now);
92671
92671
  const scheduleTimeZone = definition2.schedule.type === "cron" ? definition2.schedule.timeZone : timeZone;
92672
- const when = operation.action === "run_now" ? "Now" : scheduleText(definition2.schedule, timeZone);
92672
+ const when2 = operation.action === "run_now" ? "Now" : scheduleText(definition2.schedule, timeZone);
92673
92673
  const destination = definition2.runOn === "cloud" ? "Box-hosted agent" : "Bot\u2019s current model and configured computer";
92674
92674
  const current4 = operation.action === "create" ? null : manager.listRoutines().find((routine) => routine.id === operation.routineId) ?? null;
92675
92675
  const remainsPaused = operation.action === "update" && current4?.enabled === false;
@@ -92681,12 +92681,12 @@ Name: ${name2}`,
92681
92681
  const runLimit = definition2.timeoutMinutes === void 0 ? "no run limit" : `${definition2.timeoutMinutes} min limit`;
92682
92682
  return {
92683
92683
  title,
92684
- summary: `${actionLabel} \u201C${name2}\u201D${forSuffix} \xB7 ${when} \xB7 ${destination} \xB7 ${runLimit}${status}`,
92684
+ summary: `${actionLabel} \u201C${name2}\u201D${forSuffix} \xB7 ${when2} \xB7 ${destination} \xB7 ${runLimit}${status}`,
92685
92685
  detail: [
92686
92686
  `Action: ${actionCopy.detail}`,
92687
92687
  `Name: ${name2}`,
92688
92688
  ...forBot ? [`For: @${redactSecretsInText(forBot.name)} \u2014 each run uses that bot's engine and permissions`] : [],
92689
- `Schedule: ${when}`,
92689
+ `Schedule: ${when2}`,
92690
92690
  `Next run: ${nextDescription}`,
92691
92691
  ...definition2.schedule.type === "cron" && nextRunAt !== null && operation.action !== "run_now" ? [`Next 3 runs (${scheduleTimeZone}): ${nextCronRuns(definition2.schedule, now, 3).map((at2) => formatInstant(at2, scheduleTimeZone)).join(" \xB7 ")}`] : [],
92692
92692
  `Runs on: ${destination}`,
@@ -93229,12 +93229,12 @@ function taskDescription(routine, bot, timeZone) {
93229
93229
  ].join("\n");
93230
93230
  }
93231
93231
  function runComment(run7) {
93232
- const when = new Date(run7.finishedAt ?? run7.scheduledFor).toISOString();
93232
+ const when2 = new Date(run7.finishedAt ?? run7.scheduledFor).toISOString();
93233
93233
  const body = (run7.status === "failed" ? run7.error ?? run7.output : run7.output ?? run7.error)?.trim();
93234
93234
  const clipped = body && body.length > MAX_COMMENT_CHARS ? `${body.slice(0, MAX_COMMENT_CHARS)}
93235
93235
 
93236
93236
  (cut short; the full report is in Atomic)` : body;
93237
- return `Run ${run7.status} \xB7 ${when}${run7.manual ? " \xB7 started by hand" : ""}${clipped ? `
93237
+ return `Run ${run7.status} \xB7 ${when2}${run7.manual ? " \xB7 started by hand" : ""}${clipped ? `
93238
93238
 
93239
93239
  ${clipped}` : ""}`;
93240
93240
  }
@@ -113328,6 +113328,632 @@ function installNativeVault(dataDir2, port, desktopToken, fromBot) {
113328
113328
  ROUTES.push(createVaultRoutes({ store: () => runtime.store(), owner: (req, auth) => fromBot(req) ? null : runtime.owner(req, auth, desktopToken()) }));
113329
113329
  }
113330
113330
 
113331
+ // server/oauth-account-core.ts
113332
+ var HTTP_TIMEOUT_MS2 = 3e4;
113333
+ var MAX_RESULT_CHARS = 48e3;
113334
+ var MAX_JSON_BYTES = 4 * 1024 * 1024;
113335
+ var MAX_DOWNLOAD_BYTES = 8 * 1024 * 1024;
113336
+ var READS = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true };
113337
+ var CREATES = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
113338
+ var SENDS = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true };
113339
+ var accountArg = { type: "string", description: "Email address of the account to use. Optional only when this bot has exactly one account of this provider." };
113340
+ var EMAIL2 = /^[^\s@<>,;"]+@[^\s@<>,;"]+\.[^\s@<>,;"]+$/;
113341
+ var noNewlines = (value) => !/[\r\n]/.test(value);
113342
+ var base4 = external_exports.object({ account: external_exports.string().max(320).optional() });
113343
+ var ToolInputError = class extends Error {
113344
+ };
113345
+ function bounded2(text17, limit = MAX_RESULT_CHARS) {
113346
+ return text17.length <= limit ? text17 : `${text17.slice(0, limit)}
113347
+ [truncated: ask for less]`;
113348
+ }
113349
+ function addresses(value, field) {
113350
+ if (value === void 0) return [];
113351
+ const list3 = (Array.isArray(value) ? value : value.split(",")).map((item) => item.trim()).filter(Boolean);
113352
+ if (list3.length > 50) throw new ToolInputError(`${field}: at most 50 addresses`);
113353
+ for (const item of list3) {
113354
+ if (!EMAIL2.test(item)) throw new ToolInputError(`${field}: "${item.slice(0, 80)}" is not an email address`);
113355
+ }
113356
+ return list3;
113357
+ }
113358
+ var ProviderApiError = class extends Error {
113359
+ status;
113360
+ constructor(status, message4) {
113361
+ super(message4);
113362
+ this.status = status;
113363
+ }
113364
+ };
113365
+ async function readLimited(response, limit) {
113366
+ const declared = Number(response.headers.get("content-length") ?? "0");
113367
+ if (declared > limit) {
113368
+ await response.body?.cancel().catch(() => {
113369
+ });
113370
+ return null;
113371
+ }
113372
+ if (!response.body) return Buffer.alloc(0);
113373
+ const reader = response.body.getReader();
113374
+ const chunks = [];
113375
+ let size = 0;
113376
+ for (; ; ) {
113377
+ const { done, value } = await reader.read();
113378
+ if (done) break;
113379
+ size += value.byteLength;
113380
+ if (size > limit) {
113381
+ await reader.cancel().catch(() => {
113382
+ });
113383
+ return null;
113384
+ }
113385
+ chunks.push(value);
113386
+ }
113387
+ return Buffer.concat(chunks);
113388
+ }
113389
+ function providerErrorMessage(body, status) {
113390
+ const error51 = body?.error;
113391
+ const message4 = typeof error51 === "string" ? error51 : error51 && typeof error51 === "object" && typeof error51.message === "string" ? error51.message : "";
113392
+ return (message4 || `request failed with HTTP ${status}`).split(/\r?\n/)[0].slice(0, 300);
113393
+ }
113394
+ async function call(ctx, account2, url2, init) {
113395
+ const fetcher = ctx.fetch ?? fetch;
113396
+ const { expect, ...request4 } = init;
113397
+ for (let attempt = 0; attempt < 2; attempt += 1) {
113398
+ const token = await ctx.accessToken(account2.id);
113399
+ const headers = new Headers(request4.headers);
113400
+ headers.set("authorization", `Bearer ${token}`);
113401
+ if (!headers.has("accept") && expect === "json") headers.set("accept", "application/json");
113402
+ const response = await fetcher(url2, { ...request4, headers, signal: AbortSignal.timeout(HTTP_TIMEOUT_MS2) });
113403
+ if (response.status === 401 && attempt === 0) {
113404
+ await response.body?.cancel().catch(() => {
113405
+ });
113406
+ ctx.invalidate(account2.id);
113407
+ continue;
113408
+ }
113409
+ if (!response.ok) {
113410
+ const raw = await readLimited(response, 64 * 1024);
113411
+ let body = null;
113412
+ try {
113413
+ body = raw ? JSON.parse(raw.toString("utf8")) : null;
113414
+ } catch {
113415
+ body = null;
113416
+ }
113417
+ const message4 = providerErrorMessage(body, response.status);
113418
+ if (response.status === 403) throw new ProviderApiError(403, `${account2.email} does not allow this: ${message4}`);
113419
+ if (response.status === 404) throw new ProviderApiError(404, `Not found in ${account2.email}: ${message4}`);
113420
+ throw new ProviderApiError(response.status, `${OAUTH_PROVIDERS[account2.provider].label} refused the request for ${account2.email}: ${message4}`);
113421
+ }
113422
+ if (expect === "none") {
113423
+ await response.body?.cancel().catch(() => {
113424
+ });
113425
+ return void 0;
113426
+ }
113427
+ const bytes2 = await readLimited(response, expect === "json" ? MAX_JSON_BYTES : MAX_DOWNLOAD_BYTES);
113428
+ if (expect === "bytes") return bytes2;
113429
+ if (!bytes2) throw new ProviderApiError(502, "The response was too large");
113430
+ try {
113431
+ return JSON.parse(bytes2.toString("utf8"));
113432
+ } catch {
113433
+ throw new ProviderApiError(502, "The service returned an unreadable response");
113434
+ }
113435
+ }
113436
+ throw new ProviderApiError(401, `${account2.email} needs to sign in again: open Settings \u2192 Accounts and connect it again.`);
113437
+ }
113438
+ function parse7(schema5, value, what) {
113439
+ const parsed = schema5.safeParse(value);
113440
+ if (!parsed.success) throw new ProviderApiError(502, `Unexpected ${what} response`);
113441
+ return parsed.data;
113442
+ }
113443
+ function json4(value) {
113444
+ return JSON.stringify(value, null, 1);
113445
+ }
113446
+ function htmlToText(html) {
113447
+ return html.replace(/<(script|style)[\s\S]*?<\/\1>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|tr|li|h\d)>/gi, "\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\n{3,}/g, "\n\n").trim();
113448
+ }
113449
+ var GRAPH = "https://graph.microsoft.com/v1.0";
113450
+ var graphRecipient = external_exports.object({ emailAddress: external_exports.object({ address: external_exports.string().optional(), name: external_exports.string().optional() }).optional() });
113451
+ function recipient(value) {
113452
+ const address2 = value?.emailAddress?.address;
113453
+ const name2 = value?.emailAddress?.name;
113454
+ return address2 ? name2 && name2 !== address2 ? `${name2} <${address2}>` : address2 : void 0;
113455
+ }
113456
+
113457
+ // server/oauth-calendar-tools.ts
113458
+ var CALENDAR = "https://www.googleapis.com/calendar/v3";
113459
+ function isoInstant(value) {
113460
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) && Number.isFinite(Date.parse(value));
113461
+ }
113462
+ function isoDateOrTime(value) {
113463
+ return /^\d{4}-\d{2}-\d{2}$/.test(value) || /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})?$/.test(value);
113464
+ }
113465
+ var listEventsArgs = base4.extend({
113466
+ timeMin: external_exports.string().refine(isoInstant, "timeMin must be an ISO 8601 date-time with a time zone, e.g. 2026-10-01T00:00:00Z"),
113467
+ timeMax: external_exports.string().refine(isoInstant, "timeMax must be an ISO 8601 date-time with a time zone, e.g. 2026-10-08T00:00:00Z"),
113468
+ calendarId: external_exports.string().min(1).max(320).optional(),
113469
+ max: external_exports.number().int().min(1).max(100).optional()
113470
+ }).strict();
113471
+ var createEventArgs = base4.extend({
113472
+ summary: external_exports.string().min(1).max(1e3).refine(noNewlines, "summary must be one line"),
113473
+ start: external_exports.string().refine(isoDateOrTime, "start must be YYYY-MM-DD or an ISO 8601 date-time"),
113474
+ end: external_exports.string().refine(isoDateOrTime, "end must be YYYY-MM-DD or an ISO 8601 date-time"),
113475
+ timeZone: external_exports.string().min(1).max(64).regex(/^[A-Za-z0-9_+\-/ ]+$/).optional(),
113476
+ description: external_exports.string().max(8e3).optional(),
113477
+ location: external_exports.string().max(1e3).optional(),
113478
+ attendees: external_exports.array(external_exports.string()).max(50).optional(),
113479
+ calendarId: external_exports.string().min(1).max(320).optional()
113480
+ }).strict();
113481
+ var eventArgs = base4.extend({ id: external_exports.string().min(1).max(512).regex(/^[A-Za-z0-9!_.=+\-/~:]+$/, "not a valid id"), calendarId: external_exports.string().min(1).max(320).optional() }).strict();
113482
+ var scopeArg = external_exports.enum(["occurrence", "following", "series"]).optional();
113483
+ var notifyArg = external_exports.enum(["all", "externalOnly", "none"]);
113484
+ var updateEventArgs = eventArgs.extend({
113485
+ scope: scopeArg,
113486
+ notify: notifyArg,
113487
+ summary: createEventArgs.shape.summary.optional(),
113488
+ start: createEventArgs.shape.start.optional(),
113489
+ end: createEventArgs.shape.end.optional(),
113490
+ timeZone: createEventArgs.shape.timeZone,
113491
+ description: createEventArgs.shape.description,
113492
+ location: createEventArgs.shape.location,
113493
+ attendees: external_exports.array(external_exports.string()).max(50).optional(),
113494
+ addAttendees: external_exports.array(external_exports.string()).max(50).optional(),
113495
+ removeAttendees: external_exports.array(external_exports.string()).max(50).optional(),
113496
+ room: external_exports.string().max(320).optional()
113497
+ }).strict();
113498
+ var deleteEventArgs = eventArgs.extend({ scope: scopeArg, notify: notifyArg }).strict();
113499
+ var outlookUpdateEventArgs = updateEventArgs.omit({ calendarId: true }).extend({ notify: external_exports.literal("all") }).strict();
113500
+ var outlookDeleteEventArgs = deleteEventArgs.omit({ calendarId: true }).extend({ notify: external_exports.literal("all") }).strict();
113501
+ var listEventsSchema = (withCalendar) => ({
113502
+ type: "object",
113503
+ properties: {
113504
+ account: accountArg,
113505
+ timeMin: { type: "string", description: "Start of the window, ISO 8601 with a time zone (e.g. 2026-10-01T00:00:00Z)." },
113506
+ timeMax: { type: "string", description: "End of the window, ISO 8601 with a time zone." },
113507
+ ...withCalendar ? { calendarId: { type: "string", description: "Calendar id; defaults to the primary calendar." } } : {},
113508
+ max: { type: "integer", minimum: 1, maximum: 100, description: "Most events to return (default 25)." }
113509
+ },
113510
+ required: ["timeMin", "timeMax"],
113511
+ additionalProperties: false
113512
+ });
113513
+ var createEventSchema = (withCalendar) => ({
113514
+ type: "object",
113515
+ properties: {
113516
+ account: accountArg,
113517
+ summary: { type: "string", description: "Event title." },
113518
+ start: { type: "string", description: "YYYY-MM-DD for an all-day event, or an ISO 8601 date-time. Without an offset, pass timeZone." },
113519
+ end: { type: "string", description: "Same format as start. For all-day events this is the day after the last day." },
113520
+ timeZone: { type: "string", description: "IANA time zone such as America/Los_Angeles, used when start/end have no offset." },
113521
+ description: { type: "string" },
113522
+ location: { type: "string" },
113523
+ attendees: { type: "array", items: { type: "string" }, description: "Guest email addresses. They receive an invitation." },
113524
+ ...withCalendar ? { calendarId: { type: "string", description: "Calendar id; defaults to the primary calendar." } } : {}
113525
+ },
113526
+ required: ["summary", "start", "end"],
113527
+ additionalProperties: false
113528
+ });
113529
+ var calendarProp = { calendarId: { type: "string", description: "Calendar id; defaults to the primary calendar." } };
113530
+ var eventIdProp = { type: "string", description: "Event id from the list tool: one occurrence of a recurring event, or a single event." };
113531
+ var scopeProp = {
113532
+ type: "string",
113533
+ enum: ["occurrence", "following", "series"],
113534
+ description: "For a recurring event: this occurrence only (default), this and following, or the whole series. Pass the occurrence's id either way; the series is found from it."
113535
+ };
113536
+ var notifyProp = (outlook) => outlook ? { type: "string", enum: ["all"], description: "Outlook always tells the guests about the organizer's changes; pass all to go ahead." } : { type: "string", enum: ["all", "externalOnly", "none"], description: "Who gets an email about the change: all guests, only guests outside your organization, or nobody." };
113537
+ var eventSchema = (withCalendar) => ({
113538
+ type: "object",
113539
+ properties: { account: accountArg, id: eventIdProp, ...withCalendar ? calendarProp : {} },
113540
+ required: ["id"],
113541
+ additionalProperties: false
113542
+ });
113543
+ var updateEventSchema = (withCalendar) => ({
113544
+ type: "object",
113545
+ properties: {
113546
+ account: accountArg,
113547
+ id: eventIdProp,
113548
+ ...withCalendar ? calendarProp : {},
113549
+ scope: scopeProp,
113550
+ notify: notifyProp(!withCalendar),
113551
+ summary: { type: "string", description: "New title." },
113552
+ description: { type: "string", description: "New description; replaces the old one." },
113553
+ location: { type: "string" },
113554
+ start: { type: "string", description: "New start, same format as when creating. Pass start and end together. To move a whole series, give a UTC offset." },
113555
+ end: { type: "string", description: "New end, same format as start." },
113556
+ timeZone: { type: "string", description: "IANA time zone for start/end without an offset." },
113557
+ attendees: { type: "array", items: { type: "string" }, description: "Replace the whole guest list with these addresses. Guests who stay keep their reply." },
113558
+ addAttendees: { type: "array", items: { type: "string" }, description: "Guests to add." },
113559
+ removeAttendees: { type: "array", items: { type: "string" }, description: "Guests to remove." },
113560
+ room: { type: "string", description: "Room or resource email address; replaces the room already booked." }
113561
+ },
113562
+ required: ["id", "notify"],
113563
+ additionalProperties: false
113564
+ });
113565
+ var deleteEventSchema = (withCalendar) => ({
113566
+ type: "object",
113567
+ properties: { account: accountArg, id: eventIdProp, ...withCalendar ? calendarProp : {}, scope: scopeProp, notify: notifyProp(!withCalendar) },
113568
+ required: ["id", "notify"],
113569
+ additionalProperties: false
113570
+ });
113571
+ var GOOGLE_CALENDAR_TOOLS = [
113572
+ { name: "calendar_list_events", provider: "google", family: "calendar", description: "List Google Calendar events between two times.", inputSchema: listEventsSchema(true), annotations: READS, args: listEventsArgs },
113573
+ { name: "calendar_create_event", provider: "google", family: "calendar", description: "Create a Google Calendar event. Attendees receive an invitation.", inputSchema: createEventSchema(true), annotations: SENDS, args: createEventArgs },
113574
+ { name: "calendar_get_event", provider: "google", family: "calendar", description: "Read one Google Calendar event by id: details, its series (recurringEventId, recurrence) and each guest's reply.", inputSchema: eventSchema(true), annotations: READS, args: eventArgs },
113575
+ { name: "calendar_update_event", provider: "google", family: "calendar", description: "Change a Google Calendar event: title, description, location, times, guests or room, for one occurrence, this and following, or the whole series. notify chooses who is emailed.", inputSchema: updateEventSchema(true), annotations: SENDS, args: updateEventArgs },
113576
+ { name: "calendar_delete_event", provider: "google", family: "calendar", description: "Cancel a Google Calendar event: one occurrence, this and following, or the whole series. notify chooses who is emailed.", inputSchema: deleteEventSchema(true), annotations: SENDS, args: deleteEventArgs }
113577
+ ];
113578
+ var OUTLOOK_CALENDAR_TOOLS = [
113579
+ { name: "outlook_calendar_list_events", provider: "microsoft", family: "outlookCalendar", description: "List Outlook calendar events between two times (times are returned in UTC).", inputSchema: listEventsSchema(false), annotations: READS, args: listEventsArgs.omit({ calendarId: true }) },
113580
+ { name: "outlook_calendar_create_event", provider: "microsoft", family: "outlookCalendar", description: "Create an Outlook calendar event. Attendees receive an invitation.", inputSchema: createEventSchema(false), annotations: SENDS, args: createEventArgs.omit({ calendarId: true }) },
113581
+ { name: "outlook_calendar_get_event", provider: "microsoft", family: "outlookCalendar", description: "Read one Outlook calendar event by id: details, its series (seriesMasterId, recurrence) and each guest's reply (times in UTC).", inputSchema: eventSchema(false), annotations: READS, args: eventArgs.omit({ calendarId: true }) },
113582
+ { name: "outlook_calendar_update_event", provider: "microsoft", family: "outlookCalendar", description: "Change an Outlook calendar event: title, description, location, times, guests or room, for one occurrence, this and following, or the whole series. Guests are told.", inputSchema: updateEventSchema(false), annotations: SENDS, args: outlookUpdateEventArgs },
113583
+ { name: "outlook_calendar_delete_event", provider: "microsoft", family: "outlookCalendar", description: "Cancel an Outlook calendar event: one occurrence, this and following, or the whole series. Guests are told.", inputSchema: deleteEventSchema(false), annotations: SENDS, args: outlookDeleteEventArgs }
113584
+ ];
113585
+ function guestEdit(args) {
113586
+ const replace = args.attendees === void 0 ? void 0 : addresses(args.attendees, "attendees");
113587
+ const add3 = addresses(args.addAttendees, "addAttendees");
113588
+ const remove = addresses(args.removeAttendees, "removeAttendees");
113589
+ const room = args.room === void 0 ? void 0 : addresses(args.room, "room")[0];
113590
+ if (replace && (add3.length || remove.length)) throw new ToolInputError("Pass attendees to replace the guest list, or addAttendees/removeAttendees, not both");
113591
+ return replace || add3.length || remove.length || room ? { replace, add: add3, remove, room } : null;
113592
+ }
113593
+ function editGuests(current4, email3, isRoom, make, edit) {
113594
+ const same = (a, b3) => a.toLowerCase() === b3.toLowerCase();
113595
+ const people = current4.filter((guest) => !isRoom(guest));
113596
+ let next;
113597
+ if (edit.replace) {
113598
+ next = edit.replace.map((address2) => people.find((guest) => same(email3(guest), address2)) ?? make(address2, false));
113599
+ } else {
113600
+ for (const address2 of edit.remove) {
113601
+ if (!people.some((guest) => same(email3(guest), address2))) throw new ToolInputError(`removeAttendees: ${address2} is not a guest of this event`);
113602
+ }
113603
+ next = people.filter((guest) => !edit.remove.some((address2) => same(email3(guest), address2)));
113604
+ for (const address2 of edit.add) if (!next.some((guest) => same(email3(guest), address2))) next.push(make(address2, false));
113605
+ }
113606
+ return [...next, ...edit.room ? [make(edit.room, true)] : current4.filter(isRoom)];
113607
+ }
113608
+ function needsChange(args, fields) {
113609
+ if (!Object.keys(fields).length && args.start === void 0 && args.end === void 0) throw new ToolInputError("Nothing to change: pass at least one field to update");
113610
+ if (args.start === void 0 !== (args.end === void 0)) throw new ToolInputError("Pass start and end together");
113611
+ }
113612
+ var DATE = /^\d{4}-\d{2}-\d{2}$/;
113613
+ var millis = (value) => Date.parse(DATE.test(value) ? `${value}T00:00:00Z` : /(?:Z|[+-]\d{2}:\d{2})$/.test(value) ? value : `${value.slice(0, 19)}Z`);
113614
+ function shiftSeries(seriesStart, occurrenceStart, allDay, start, end) {
113615
+ if (DATE.test(start) !== allDay) throw new ToolInputError("A whole series cannot switch between all-day and timed; change one occurrence or this and following");
113616
+ if (!allDay && !/(?:Z|[+-]\d{2}:\d{2})$/.test(start)) throw new ToolInputError("start: to move a whole series, give a UTC offset (e.g. 2026-10-01T15:00:00-07:00)");
113617
+ const moved = millis(seriesStart) + millis(start) - millis(occurrenceStart);
113618
+ return [moved, moved + millis(end) - millis(start)];
113619
+ }
113620
+ function dayBefore(date5) {
113621
+ const day = /* @__PURE__ */ new Date(`${date5}T00:00:00Z`);
113622
+ day.setUTCDate(day.getUTCDate() - 1);
113623
+ return day.toISOString().slice(0, 10);
113624
+ }
113625
+ var googleTime = external_exports.object({ dateTime: external_exports.string().optional(), date: external_exports.string().optional(), timeZone: external_exports.string().optional() });
113626
+ var googleAttendee = external_exports.object({ email: external_exports.string().optional(), responseStatus: external_exports.string().optional(), resource: external_exports.boolean().optional() }).passthrough();
113627
+ var googleEventSchema = external_exports.object({
113628
+ id: external_exports.string(),
113629
+ summary: external_exports.string().optional(),
113630
+ description: external_exports.string().optional(),
113631
+ location: external_exports.string().optional(),
113632
+ status: external_exports.string().optional(),
113633
+ htmlLink: external_exports.string().optional(),
113634
+ start: googleTime.optional(),
113635
+ end: googleTime.optional(),
113636
+ organizer: external_exports.object({ email: external_exports.string().optional() }).optional(),
113637
+ attendees: external_exports.array(googleAttendee).optional(),
113638
+ recurringEventId: external_exports.string().optional(),
113639
+ originalStartTime: googleTime.optional(),
113640
+ recurrence: external_exports.array(external_exports.string()).optional()
113641
+ }).passthrough();
113642
+ function googleEvent(event) {
113643
+ return {
113644
+ id: event.id,
113645
+ summary: event.summary,
113646
+ start: event.start?.dateTime ?? event.start?.date,
113647
+ end: event.end?.dateTime ?? event.end?.date,
113648
+ location: event.location,
113649
+ organizer: event.organizer?.email,
113650
+ attendees: event.attendees?.map((attendee) => `${attendee.email ?? ""}${attendee.resource ? " (room)" : ""}${attendee.responseStatus ? ` (${attendee.responseStatus})` : ""}`),
113651
+ description: event.description ? bounded2(event.description, 2e3) : void 0,
113652
+ recurringEventId: event.recurringEventId,
113653
+ recurrence: event.recurrence,
113654
+ link: event.htmlLink
113655
+ };
113656
+ }
113657
+ async function calendarListEvents(ctx, account2, args) {
113658
+ const calendarId = encodeURIComponent(args.calendarId ?? "primary");
113659
+ const query = new URLSearchParams({ timeMin: args.timeMin, timeMax: args.timeMax, singleEvents: "true", orderBy: "startTime", maxResults: String(args.max ?? 25) });
113660
+ const list3 = parse7(external_exports.object({ items: external_exports.array(googleEventSchema).optional(), timeZone: external_exports.string().optional() }), await call(ctx, account2, `${CALENDAR}/calendars/${calendarId}/events?${query}`, { expect: "json" }), "Calendar");
113661
+ return json4({ account: account2.email, timeZone: list3.timeZone, events: (list3.items ?? []).map(googleEvent) });
113662
+ }
113663
+ function eventTime(value, timeZone, field) {
113664
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return { allDay: true, date: value };
113665
+ const hasOffset = /(?:Z|[+-]\d{2}:\d{2})$/.test(value);
113666
+ if (!hasOffset && !timeZone) throw new ToolInputError(`${field}: add a UTC offset (e.g. 2026-10-01T15:00:00-07:00) or pass timeZone`);
113667
+ return { allDay: false, dateTime: value, hasOffset };
113668
+ }
113669
+ function googleTimes(startValue, endValue, timeZone) {
113670
+ const start = eventTime(startValue, timeZone, "start");
113671
+ const end = eventTime(endValue, timeZone, "end");
113672
+ if (start.allDay !== end.allDay) throw new ToolInputError("start and end must both be dates or both be date-times");
113673
+ const time4 = (value) => value.allDay ? { date: value.date } : { dateTime: value.dateTime, ...timeZone ? { timeZone } : {} };
113674
+ return { start: time4(start), end: time4(end) };
113675
+ }
113676
+ async function calendarCreateEvent(ctx, account2, args) {
113677
+ const attendees = addresses(args.attendees, "attendees");
113678
+ const body = {
113679
+ summary: args.summary,
113680
+ ...args.description ? { description: args.description } : {},
113681
+ ...args.location ? { location: args.location } : {},
113682
+ ...googleTimes(args.start, args.end, args.timeZone),
113683
+ ...attendees.length ? { attendees: attendees.map((email3) => ({ email: email3 })) } : {}
113684
+ };
113685
+ const calendarId = encodeURIComponent(args.calendarId ?? "primary");
113686
+ const query = new URLSearchParams({ sendUpdates: attendees.length ? "all" : "none" });
113687
+ const created = parse7(googleEventSchema, await call(ctx, account2, `${CALENDAR}/calendars/${calendarId}/events?${query}`, {
113688
+ method: "POST",
113689
+ headers: { "content-type": "application/json" },
113690
+ body: JSON.stringify(body),
113691
+ expect: "json"
113692
+ }), "Calendar");
113693
+ return json4({ account: account2.email, created: googleEvent(created) });
113694
+ }
113695
+ var eventUrl = (calendarId, id, query) => `${CALENDAR}/calendars/${encodeURIComponent(calendarId ?? "primary")}/events${id ? `/${encodeURIComponent(id)}` : ""}${query ? `?${new URLSearchParams(query)}` : ""}`;
113696
+ var when = (time4) => time4?.dateTime ?? time4?.date ?? "";
113697
+ async function googleGet(ctx, account2, calendarId, id) {
113698
+ return parse7(googleEventSchema, await call(ctx, account2, eventUrl(calendarId, id), { expect: "json" }), "Calendar");
113699
+ }
113700
+ async function googleSave(ctx, account2, method, url2, body) {
113701
+ return parse7(googleEventSchema, await call(ctx, account2, url2, { method, headers: { "content-type": "application/json" }, body: JSON.stringify(body), expect: "json" }), "Calendar");
113702
+ }
113703
+ async function googleTarget(ctx, account2, args) {
113704
+ const scope = args.scope ?? "occurrence";
113705
+ const event = await googleGet(ctx, account2, args.calendarId, args.id);
113706
+ if (scope === "occurrence" && event.recurrence) throw new ToolInputError(`${args.id} is a whole series: pass the id of one occurrence (from calendar_list_events), or scope "series"`);
113707
+ if (scope === "occurrence" || !event.recurringEventId && !event.recurrence) return { scope: "occurrence", event, series: event };
113708
+ const series = event.recurringEventId ? await googleGet(ctx, account2, args.calendarId, event.recurringEventId) : event;
113709
+ const first = !event.originalStartTime || millis(when(event.originalStartTime)) === millis(when(series.start));
113710
+ return { scope: first ? "series" : scope, event, series };
113711
+ }
113712
+ function googleFields(args, current4) {
113713
+ const guests = guestEdit(args);
113714
+ return {
113715
+ ...args.summary !== void 0 ? { summary: args.summary } : {},
113716
+ ...args.description !== void 0 ? { description: args.description } : {},
113717
+ ...args.location !== void 0 ? { location: args.location } : {},
113718
+ ...guests ? {
113719
+ attendees: editGuests(current4.attendees ?? [], (guest) => guest.email ?? "", (guest) => guest.resource === true, (email3, resource) => resource ? { email: email3, resource } : { email: email3 }, guests)
113720
+ } : {}
113721
+ };
113722
+ }
113723
+ function capRecurrence(rules, from) {
113724
+ const until = from.date ? dayBefore(from.date).replace(/-/g, "") : new Date(millis(from.dateTime ?? "") - 1e3).toISOString().replace(/[-:]|\.\d{3}/g, "");
113725
+ return rules.map((rule) => rule.startsWith("RRULE:") ? `RRULE:${[...rule.slice(6).split(";").filter((part) => !/^(UNTIL|COUNT)=/i.test(part)), `UNTIL=${until}`].join(";")}` : rule);
113726
+ }
113727
+ var SERIES_FIELDS = ["summary", "description", "location", "attendees", "colorId", "reminders", "transparency", "visibility", "guestsCanModify", "guestsCanInviteOthers", "guestsCanSeeOtherGuests"];
113728
+ async function calendarGetEvent(ctx, account2, args) {
113729
+ return json4({ account: account2.email, event: googleEvent(await googleGet(ctx, account2, args.calendarId, args.id)) });
113730
+ }
113731
+ async function calendarUpdateEvent(ctx, account2, args) {
113732
+ const { scope, event, series } = await googleTarget(ctx, account2, args);
113733
+ const fields = googleFields(args, series);
113734
+ needsChange(args, fields);
113735
+ const notify2 = { sendUpdates: args.notify };
113736
+ if (scope === "occurrence") {
113737
+ const times2 = args.start !== void 0 ? googleTimes(args.start, args.end, args.timeZone) : {};
113738
+ const updated = await googleSave(ctx, account2, "PATCH", eventUrl(args.calendarId, event.id, notify2), { ...fields, ...times2 });
113739
+ return json4({ account: account2.email, scope, updated: googleEvent(updated) });
113740
+ }
113741
+ if (scope === "series") {
113742
+ let times2 = {};
113743
+ if (args.start !== void 0) {
113744
+ const allDay = Boolean(event.start?.date);
113745
+ const [start, end] = shiftSeries(when(series.start), when(event.start), allDay, args.start, args.end);
113746
+ const at2 = (ms2) => allDay ? { date: new Date(ms2).toISOString().slice(0, 10) } : { dateTime: new Date(ms2).toISOString(), timeZone: args.timeZone ?? series.start?.timeZone };
113747
+ times2 = { start: at2(start), end: at2(end) };
113748
+ }
113749
+ const updated = await googleSave(ctx, account2, "PATCH", eventUrl(args.calendarId, series.id, notify2), { ...fields, ...times2 });
113750
+ return json4({ account: account2.email, scope, updated: googleEvent(updated) });
113751
+ }
113752
+ if (series.recurrence?.some((rule) => /^RRULE:.*\bCOUNT=/i.test(rule))) {
113753
+ throw new ToolInputError("This series ends after a set number of times, so it cannot be split: change one occurrence or the whole series");
113754
+ }
113755
+ const copied = Object.fromEntries(SERIES_FIELDS.filter((key5) => series[key5] !== void 0).map((key5) => [key5, series[key5]]));
113756
+ const times = args.start !== void 0 ? googleTimes(args.start, args.end, args.timeZone) : { start: event.start, end: event.end };
113757
+ const created = await googleSave(ctx, account2, "POST", eventUrl(args.calendarId, "", notify2), { ...copied, ...fields, ...times, recurrence: series.recurrence });
113758
+ await googleSave(ctx, account2, "PATCH", eventUrl(args.calendarId, series.id, notify2), { recurrence: capRecurrence(series.recurrence ?? [], event.originalStartTime ?? {}) });
113759
+ return json4({ account: account2.email, scope, updated: googleEvent(created), endedSeries: series.id, note: "The old series now ends before this occurrence; a new series with the changes starts here." });
113760
+ }
113761
+ async function calendarDeleteEvent(ctx, account2, args) {
113762
+ const { scope, event, series } = await googleTarget(ctx, account2, args);
113763
+ const notify2 = { sendUpdates: args.notify };
113764
+ if (scope === "following") {
113765
+ await googleSave(ctx, account2, "PATCH", eventUrl(args.calendarId, series.id, notify2), { recurrence: capRecurrence(series.recurrence ?? [], event.originalStartTime ?? {}) });
113766
+ } else {
113767
+ await call(ctx, account2, eventUrl(args.calendarId, (scope === "series" ? series : event).id, notify2), { method: "DELETE", expect: "none" });
113768
+ }
113769
+ return json4({ account: account2.email, cancelled: true, scope, id: scope === "occurrence" ? event.id : series.id });
113770
+ }
113771
+ var graphTime = external_exports.object({ dateTime: external_exports.string().optional(), timeZone: external_exports.string().optional() });
113772
+ var graphEventSchema = external_exports.object({
113773
+ id: external_exports.string(),
113774
+ subject: external_exports.string().nullable().optional(),
113775
+ start: graphTime.optional(),
113776
+ end: graphTime.optional(),
113777
+ isAllDay: external_exports.boolean().optional(),
113778
+ location: external_exports.object({ displayName: external_exports.string().optional() }).nullable().optional(),
113779
+ organizer: graphRecipient.nullable().optional(),
113780
+ attendees: external_exports.array(graphRecipient.extend({ type: external_exports.string().optional(), status: external_exports.object({ response: external_exports.string().optional() }).optional() })).optional(),
113781
+ webLink: external_exports.string().optional(),
113782
+ bodyPreview: external_exports.string().optional(),
113783
+ body: external_exports.object({ contentType: external_exports.string().optional(), content: external_exports.string().optional() }).optional(),
113784
+ type: external_exports.string().optional(),
113785
+ seriesMasterId: external_exports.string().nullable().optional(),
113786
+ originalStartTimeZone: external_exports.string().optional(),
113787
+ recurrence: external_exports.object({
113788
+ pattern: external_exports.record(external_exports.string(), external_exports.unknown()),
113789
+ range: external_exports.object({ type: external_exports.string(), startDate: external_exports.string().optional(), endDate: external_exports.string().optional() }).passthrough()
113790
+ }).nullable().optional()
113791
+ });
113792
+ function graphEvent(event) {
113793
+ return {
113794
+ id: event.id,
113795
+ summary: event.subject,
113796
+ start: event.start?.dateTime ? `${event.start.dateTime}${event.start.timeZone === "UTC" ? "Z" : ` (${event.start.timeZone ?? ""})`}` : void 0,
113797
+ end: event.end?.dateTime ? `${event.end.dateTime}${event.end.timeZone === "UTC" ? "Z" : ` (${event.end.timeZone ?? ""})`}` : void 0,
113798
+ allDay: event.isAllDay,
113799
+ location: event.location?.displayName || void 0,
113800
+ organizer: recipient(event.organizer),
113801
+ attendees: event.attendees?.map((attendee) => `${recipient(attendee) ?? ""}${attendee.type === "resource" ? " (room)" : ""}${attendee.status?.response ? ` (${attendee.status.response})` : ""}`),
113802
+ preview: event.bodyPreview ? bounded2(event.bodyPreview, 1e3) : void 0,
113803
+ type: event.type,
113804
+ seriesMasterId: event.seriesMasterId ?? void 0,
113805
+ recurrence: event.recurrence ?? void 0,
113806
+ link: event.webLink
113807
+ };
113808
+ }
113809
+ async function outlookListEvents(ctx, account2, args) {
113810
+ const query = new URLSearchParams({
113811
+ startDateTime: new Date(args.timeMin).toISOString(),
113812
+ endDateTime: new Date(args.timeMax).toISOString(),
113813
+ $top: String(args.max ?? 25),
113814
+ $orderby: "start/dateTime",
113815
+ $select: "id,subject,start,end,isAllDay,location,organizer,attendees,webLink,bodyPreview"
113816
+ });
113817
+ const list3 = parse7(external_exports.object({ value: external_exports.array(graphEventSchema) }), await call(ctx, account2, `${GRAPH}/me/calendarView?${query}`, {
113818
+ headers: { prefer: 'outlook.timezone="UTC"' },
113819
+ expect: "json"
113820
+ }), "Outlook calendar");
113821
+ return json4({ account: account2.email, timeZone: "UTC", events: list3.value.map(graphEvent) });
113822
+ }
113823
+ function graphDateTime(value, timeZone, field) {
113824
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return { dateTime: `${value}T00:00:00`, timeZone: timeZone ?? "UTC", allDay: true };
113825
+ if (/(?:Z|[+-]\d{2}:\d{2})$/.test(value)) {
113826
+ const parsed = Date.parse(value);
113827
+ if (!Number.isFinite(parsed)) throw new ToolInputError(`${field}: not a valid date-time`);
113828
+ return { dateTime: new Date(parsed).toISOString().replace(/\.\d{3}Z$/, ""), timeZone: "UTC", allDay: false };
113829
+ }
113830
+ if (!timeZone) throw new ToolInputError(`${field}: add a UTC offset (e.g. 2026-10-01T15:00:00-07:00) or pass timeZone`);
113831
+ return { dateTime: value, timeZone, allDay: false };
113832
+ }
113833
+ function graphTimes(startValue, endValue, timeZone) {
113834
+ const start = graphDateTime(startValue, timeZone, "start");
113835
+ const end = graphDateTime(endValue, timeZone, "end");
113836
+ if (start.allDay !== end.allDay) throw new ToolInputError("start and end must both be dates or both be date-times");
113837
+ return { start: { dateTime: start.dateTime, timeZone: start.timeZone }, end: { dateTime: end.dateTime, timeZone: end.timeZone }, isAllDay: start.allDay };
113838
+ }
113839
+ async function outlookCreateEvent(ctx, account2, args) {
113840
+ const attendees = addresses(args.attendees, "attendees");
113841
+ const created = await graphSave(ctx, account2, "POST", `${GRAPH}/me/events`, {
113842
+ subject: args.summary,
113843
+ ...args.description ? { body: { contentType: "Text", content: args.description } } : {},
113844
+ ...graphTimes(args.start, args.end, args.timeZone),
113845
+ ...args.location ? { location: { displayName: args.location } } : {},
113846
+ ...attendees.length ? { attendees: attendees.map((address2) => ({ emailAddress: { address: address2 }, type: "required" })) } : {}
113847
+ });
113848
+ return json4({ account: account2.email, created: graphEvent(created) });
113849
+ }
113850
+ var GRAPH_EVENT_FIELDS = "id,subject,start,end,isAllDay,location,organizer,attendees,webLink,bodyPreview,body,type,seriesMasterId,recurrence,originalStartTimeZone";
113851
+ var UTC = 'outlook.timezone="UTC"';
113852
+ var graphEventUrl = (id) => `${GRAPH}/me/events/${encodeURIComponent(id)}`;
113853
+ async function graphGet(ctx, account2, id, prefer = UTC) {
113854
+ return parse7(graphEventSchema, await call(ctx, account2, `${graphEventUrl(id)}?${new URLSearchParams({ $select: GRAPH_EVENT_FIELDS })}`, { headers: { prefer }, expect: "json" }), "Outlook calendar");
113855
+ }
113856
+ async function graphSave(ctx, account2, method, url2, body) {
113857
+ return parse7(graphEventSchema, await call(ctx, account2, url2, {
113858
+ method,
113859
+ headers: { "content-type": "application/json", prefer: UTC },
113860
+ body: JSON.stringify(body),
113861
+ expect: "json"
113862
+ }), "Outlook calendar");
113863
+ }
113864
+ async function graphTarget(ctx, account2, args) {
113865
+ const scope = args.scope ?? "occurrence";
113866
+ const event = await graphGet(ctx, account2, args.id);
113867
+ if (scope === "occurrence" && event.type === "seriesMaster") throw new ToolInputError(`${args.id} is a whole series: pass the id of one occurrence (from outlook_calendar_list_events), or scope "series"`);
113868
+ if (scope === "occurrence" || !event.seriesMasterId && event.type !== "seriesMaster") return { scope: "occurrence", event, series: event };
113869
+ const series = event.type === "seriesMaster" ? event : await graphGet(ctx, account2, event.seriesMasterId);
113870
+ const first = event.type === "seriesMaster" || millis(event.start?.dateTime ?? "") === millis(series.start?.dateTime ?? "");
113871
+ return { scope: first ? "series" : scope, event, series };
113872
+ }
113873
+ var graphGuests = (event) => (event.attendees ?? []).map((guest) => ({ emailAddress: { address: guest.emailAddress?.address ?? "" }, type: guest.type ?? "required" }));
113874
+ function graphFields(args, current4) {
113875
+ const guests = guestEdit(args);
113876
+ return {
113877
+ ...args.summary !== void 0 ? { subject: args.summary } : {},
113878
+ ...args.description !== void 0 ? { body: { contentType: "Text", content: args.description } } : {},
113879
+ ...args.location !== void 0 ? { location: { displayName: args.location } } : {},
113880
+ ...guests ? {
113881
+ attendees: editGuests(graphGuests(current4), (guest) => guest.emailAddress.address, (guest) => guest.type === "resource", (address2, room) => ({ emailAddress: { address: address2 }, type: room ? "resource" : "required" }), guests)
113882
+ } : {}
113883
+ };
113884
+ }
113885
+ async function seriesDay(ctx, account2, event, series) {
113886
+ const local = await graphGet(ctx, account2, event.id, `outlook.timezone="${series.originalStartTimeZone ?? "UTC"}"`);
113887
+ return { local, day: (local.start?.dateTime ?? "").slice(0, 10) };
113888
+ }
113889
+ function endSeriesBefore(series, day) {
113890
+ const recurrence = series.recurrence;
113891
+ return { recurrence: { pattern: recurrence.pattern, range: { ...recurrence.range, type: "endDate", endDate: dayBefore(day) } } };
113892
+ }
113893
+ async function outlookGetEvent(ctx, account2, args) {
113894
+ const event = await graphGet(ctx, account2, args.id, `${UTC}, outlook.body-content-type="text"`);
113895
+ return json4({ account: account2.email, timeZone: "UTC", event: { ...graphEvent(event), description: event.body?.content ? bounded2(event.body.content, 2e3) : void 0 } });
113896
+ }
113897
+ async function outlookUpdateEvent(ctx, account2, args) {
113898
+ const { scope, event, series } = await graphTarget(ctx, account2, args);
113899
+ const fields = graphFields(args, series);
113900
+ needsChange(args, fields);
113901
+ if (scope === "occurrence") {
113902
+ const updated = await graphSave(ctx, account2, "PATCH", graphEventUrl(event.id), { ...fields, ...args.start !== void 0 ? graphTimes(args.start, args.end, args.timeZone) : {} });
113903
+ return json4({ account: account2.email, scope, updated: graphEvent(updated) });
113904
+ }
113905
+ const zone = series.originalStartTimeZone ?? "UTC";
113906
+ if (scope === "series") {
113907
+ let times2 = {};
113908
+ if (args.start !== void 0) {
113909
+ const local2 = await graphGet(ctx, account2, series.id, `outlook.timezone="${zone}"`);
113910
+ const [start, end] = shiftSeries(local2.start?.dateTime ?? "", event.start?.dateTime ?? "", event.isAllDay === true, args.start, args.end);
113911
+ const at2 = (ms2) => ({ dateTime: new Date(ms2).toISOString().slice(0, 19), timeZone: zone });
113912
+ times2 = { start: at2(start), end: at2(end) };
113913
+ }
113914
+ const updated = await graphSave(ctx, account2, "PATCH", graphEventUrl(series.id), { ...fields, ...times2 });
113915
+ return json4({ account: account2.email, scope, updated: graphEvent(updated) });
113916
+ }
113917
+ if (!series.recurrence || series.recurrence.range.type === "numbered") {
113918
+ throw new ToolInputError("This series ends after a set number of times, so it cannot be split: change one occurrence or the whole series");
113919
+ }
113920
+ const { local, day } = await seriesDay(ctx, account2, event, series);
113921
+ const times = args.start !== void 0 ? graphTimes(args.start, args.end, args.timeZone) : { start: { dateTime: local.start?.dateTime, timeZone: zone }, end: { dateTime: local.end?.dateTime, timeZone: zone }, isAllDay: series.isAllDay === true };
113922
+ const created = await graphSave(ctx, account2, "POST", `${GRAPH}/me/events`, {
113923
+ subject: series.subject,
113924
+ ...series.body?.content ? { body: series.body } : {},
113925
+ ...series.location?.displayName ? { location: { displayName: series.location.displayName } } : {},
113926
+ attendees: graphGuests(series),
113927
+ ...fields,
113928
+ ...times,
113929
+ recurrence: { pattern: series.recurrence.pattern, range: { ...series.recurrence.range, startDate: day } }
113930
+ });
113931
+ await graphSave(ctx, account2, "PATCH", graphEventUrl(series.id), endSeriesBefore(series, day));
113932
+ return json4({ account: account2.email, scope, updated: graphEvent(created), endedSeries: series.id, note: "The old series now ends before this occurrence; a new series with the changes starts here." });
113933
+ }
113934
+ async function outlookDeleteEvent(ctx, account2, args) {
113935
+ const { scope, event, series } = await graphTarget(ctx, account2, args);
113936
+ if (scope === "following") {
113937
+ const { day } = await seriesDay(ctx, account2, event, series);
113938
+ await graphSave(ctx, account2, "PATCH", graphEventUrl(series.id), endSeriesBefore(series, day));
113939
+ } else {
113940
+ await call(ctx, account2, graphEventUrl((scope === "series" ? series : event).id), { method: "DELETE", expect: "none" });
113941
+ }
113942
+ return json4({ account: account2.email, cancelled: true, scope, id: scope === "occurrence" ? event.id : series.id });
113943
+ }
113944
+ var CALENDAR_RUNNERS = {
113945
+ calendar_list_events: calendarListEvents,
113946
+ calendar_create_event: calendarCreateEvent,
113947
+ calendar_get_event: calendarGetEvent,
113948
+ calendar_update_event: calendarUpdateEvent,
113949
+ calendar_delete_event: calendarDeleteEvent,
113950
+ outlook_calendar_list_events: outlookListEvents,
113951
+ outlook_calendar_create_event: outlookCreateEvent,
113952
+ outlook_calendar_get_event: outlookGetEvent,
113953
+ outlook_calendar_update_event: outlookUpdateEvent,
113954
+ outlook_calendar_delete_event: outlookDeleteEvent
113955
+ };
113956
+
113331
113957
  // server/office-text.ts
113332
113958
  import { inflateRawSync } from "node:zlib";
113333
113959
  var MAX_ENTRIES4 = 2e3;
@@ -113439,26 +114065,9 @@ ${paragraphs(files.get(name2).toString("utf8"), "a:p", "a:t")}`);
113439
114065
  }
113440
114066
 
113441
114067
  // server/oauth-account-tools.ts
113442
- var HTTP_TIMEOUT_MS2 = 3e4;
113443
- var MAX_RESULT_CHARS = 48e3;
113444
114068
  var MAX_BODY_CHARS = 2e4;
113445
114069
  var MAX_FILE_TEXT_CHARS = 4e4;
113446
- var MAX_JSON_BYTES = 4 * 1024 * 1024;
113447
- var MAX_DOWNLOAD_BYTES = 8 * 1024 * 1024;
113448
- var READS = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true };
113449
- var CREATES = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
113450
- var SENDS = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true };
113451
- var accountArg = { type: "string", description: "Email address of the account to use. Optional only when this bot has exactly one account of this provider." };
113452
114070
  var emailList = external_exports.union([external_exports.string(), external_exports.array(external_exports.string()).max(50)]);
113453
- var EMAIL2 = /^[^\s@<>,;"]+@[^\s@<>,;"]+\.[^\s@<>,;"]+$/;
113454
- var noNewlines = (value) => !/[\r\n]/.test(value);
113455
- function isoInstant(value) {
113456
- return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) && Number.isFinite(Date.parse(value));
113457
- }
113458
- function isoDateOrTime(value) {
113459
- return /^\d{4}-\d{2}-\d{2}$/.test(value) || /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})?$/.test(value);
113460
- }
113461
- var base4 = external_exports.object({ account: external_exports.string().max(320).optional() });
113462
114071
  var searchArgs = base4.extend({ q: external_exports.string().min(1).max(500), max: external_exports.number().int().min(1).max(25).optional() }).strict();
113463
114072
  var idArgs = (key5) => base4.extend({ [key5]: external_exports.string().min(1).max(512).regex(/^[A-Za-z0-9!_.=+\-/~:]+$/, "not a valid id") }).strict();
113464
114073
  var draftArgs = base4.extend({
@@ -113467,22 +114076,6 @@ var draftArgs = base4.extend({
113467
114076
  body: external_exports.string().max(2e5),
113468
114077
  cc: emailList.optional()
113469
114078
  }).strict();
113470
- var listEventsArgs = base4.extend({
113471
- timeMin: external_exports.string().refine(isoInstant, "timeMin must be an ISO 8601 date-time with a time zone, e.g. 2026-10-01T00:00:00Z"),
113472
- timeMax: external_exports.string().refine(isoInstant, "timeMax must be an ISO 8601 date-time with a time zone, e.g. 2026-10-08T00:00:00Z"),
113473
- calendarId: external_exports.string().min(1).max(320).optional(),
113474
- max: external_exports.number().int().min(1).max(100).optional()
113475
- }).strict();
113476
- var createEventArgs = base4.extend({
113477
- summary: external_exports.string().min(1).max(1e3).refine(noNewlines, "summary must be one line"),
113478
- start: external_exports.string().refine(isoDateOrTime, "start must be YYYY-MM-DD or an ISO 8601 date-time"),
113479
- end: external_exports.string().refine(isoDateOrTime, "end must be YYYY-MM-DD or an ISO 8601 date-time"),
113480
- timeZone: external_exports.string().min(1).max(64).regex(/^[A-Za-z0-9_+\-/ ]+$/).optional(),
113481
- description: external_exports.string().max(8e3).optional(),
113482
- location: external_exports.string().max(1e3).optional(),
113483
- attendees: external_exports.array(external_exports.string()).max(50).optional(),
113484
- calendarId: external_exports.string().min(1).max(320).optional()
113485
- }).strict();
113486
114079
  var listAccountsArgs = external_exports.object({}).strict();
113487
114080
  var searchSchema = (what) => ({
113488
114081
  type: "object",
@@ -113503,50 +114096,20 @@ var draftSchema = {
113503
114096
  required: ["to", "subject", "body"],
113504
114097
  additionalProperties: false
113505
114098
  };
113506
- var listEventsSchema = (withCalendar) => ({
113507
- type: "object",
113508
- properties: {
113509
- account: accountArg,
113510
- timeMin: { type: "string", description: "Start of the window, ISO 8601 with a time zone (e.g. 2026-10-01T00:00:00Z)." },
113511
- timeMax: { type: "string", description: "End of the window, ISO 8601 with a time zone." },
113512
- ...withCalendar ? { calendarId: { type: "string", description: "Calendar id; defaults to the primary calendar." } } : {},
113513
- max: { type: "integer", minimum: 1, maximum: 100, description: "Most events to return (default 25)." }
113514
- },
113515
- required: ["timeMin", "timeMax"],
113516
- additionalProperties: false
113517
- });
113518
- var createEventSchema = (withCalendar) => ({
113519
- type: "object",
113520
- properties: {
113521
- account: accountArg,
113522
- summary: { type: "string", description: "Event title." },
113523
- start: { type: "string", description: "YYYY-MM-DD for an all-day event, or an ISO 8601 date-time. Without an offset, pass timeZone." },
113524
- end: { type: "string", description: "Same format as start. For all-day events this is the day after the last day." },
113525
- timeZone: { type: "string", description: "IANA time zone such as America/Los_Angeles, used when start/end have no offset." },
113526
- description: { type: "string" },
113527
- location: { type: "string" },
113528
- attendees: { type: "array", items: { type: "string" }, description: "Guest email addresses. They receive an invitation." },
113529
- ...withCalendar ? { calendarId: { type: "string", description: "Calendar id; defaults to the primary calendar." } } : {}
113530
- },
113531
- required: ["summary", "start", "end"],
113532
- additionalProperties: false
113533
- });
113534
114099
  var ACCOUNT_TOOLS = [
113535
114100
  { name: "list_accounts", provider: null, description: "List the Google and Microsoft accounts this bot may use, by email.", inputSchema: { type: "object", properties: {}, additionalProperties: false }, annotations: READS, args: listAccountsArgs },
113536
114101
  { name: "gmail_search", provider: "google", family: "gmail", description: "Search Gmail with Gmail search syntax (e.g. from:alex newer_than:7d). Returns message ids, senders, subjects, dates and snippets.", inputSchema: searchSchema("Gmail search query."), annotations: READS, args: searchArgs },
113537
114102
  { name: "gmail_read", provider: "google", family: "gmail", description: "Read one Gmail message by id: headers, plain-text body and attachment names.", inputSchema: idSchema("id", "Message id from gmail_search."), annotations: READS, args: idArgs("id") },
113538
114103
  { name: "gmail_create_draft", provider: "google", family: "gmailSend", description: "Create a plain-text Gmail draft. Nothing is sent until gmail_send_draft.", inputSchema: draftSchema, annotations: CREATES, args: draftArgs },
113539
114104
  { name: "gmail_send_draft", provider: "google", family: "gmailSend", description: "Send an existing Gmail draft by its draft id.", inputSchema: idSchema("draftId", "Draft id from gmail_create_draft."), annotations: SENDS, args: idArgs("draftId") },
113540
- { name: "calendar_list_events", provider: "google", family: "calendar", description: "List Google Calendar events between two times.", inputSchema: listEventsSchema(true), annotations: READS, args: listEventsArgs },
113541
- { name: "calendar_create_event", provider: "google", family: "calendar", description: "Create a Google Calendar event. Attendees receive an invitation.", inputSchema: createEventSchema(true), annotations: SENDS, args: createEventArgs },
114105
+ ...GOOGLE_CALENDAR_TOOLS,
113542
114106
  { name: "drive_search", provider: "google", family: "drive", description: "Search Google Drive files by words in their name or content.", inputSchema: searchSchema("Words to look for."), annotations: READS, args: searchArgs },
113543
114107
  { name: "drive_read", provider: "google", family: "drive", description: "Read a Google Drive file by id: text for Docs, Sheets (CSV), Slides, Office and text files; details and a link otherwise.", inputSchema: idSchema("fileId", "File id from drive_search."), annotations: READS, args: idArgs("fileId") },
113544
114108
  { name: "outlook_search", provider: "microsoft", family: "outlook", description: "Search Outlook mail by words (sender, subject, body). Returns message ids, senders, subjects, dates and previews.", inputSchema: searchSchema("Words to search for."), annotations: READS, args: searchArgs },
113545
114109
  { name: "outlook_read", provider: "microsoft", family: "outlook", description: "Read one Outlook message by id: headers and plain-text body.", inputSchema: idSchema("id", "Message id from outlook_search."), annotations: READS, args: idArgs("id") },
113546
114110
  { name: "outlook_create_draft", provider: "microsoft", family: "outlook", description: "Create a plain-text Outlook draft. Nothing is sent until outlook_send_draft.", inputSchema: draftSchema, annotations: CREATES, args: draftArgs },
113547
114111
  { name: "outlook_send_draft", provider: "microsoft", family: "outlook", description: "Send an existing Outlook draft by its id.", inputSchema: idSchema("draftId", "Draft id from outlook_create_draft."), annotations: SENDS, args: idArgs("draftId") },
113548
- { name: "outlook_calendar_list_events", provider: "microsoft", family: "outlookCalendar", description: "List Outlook calendar events between two times (times are returned in UTC).", inputSchema: listEventsSchema(false), annotations: READS, args: listEventsArgs.omit({ calendarId: true }) },
113549
- { name: "outlook_calendar_create_event", provider: "microsoft", family: "outlookCalendar", description: "Create an Outlook calendar event. Attendees receive an invitation.", inputSchema: createEventSchema(false), annotations: SENDS, args: createEventArgs.omit({ calendarId: true }) },
114112
+ ...OUTLOOK_CALENDAR_TOOLS,
113550
114113
  { name: "onedrive_search", provider: "microsoft", family: "onedrive", description: "Search OneDrive files by words in their name or content.", inputSchema: searchSchema("Words to look for."), annotations: READS, args: searchArgs },
113551
114114
  { name: "onedrive_read", provider: "microsoft", family: "onedrive", description: "Read a OneDrive file by id: text for small text and Office files, details and a link otherwise.", inputSchema: idSchema("fileId", "File id from onedrive_search."), annotations: READS, args: idArgs("fileId") }
113552
114115
  ];
@@ -113557,12 +114120,6 @@ function accountToolList(providers) {
113557
114120
  function isReadOnlyAccountTool(name2) {
113558
114121
  return TOOL_BY_NAME.get(name2)?.annotations.readOnlyHint === true;
113559
114122
  }
113560
- var ToolInputError = class extends Error {
113561
- };
113562
- function bounded2(text17, limit = MAX_RESULT_CHARS) {
113563
- return text17.length <= limit ? text17 : `${text17.slice(0, limit)}
113564
- [truncated: ask for less]`;
113565
- }
113566
114123
  function describeIssues(error51) {
113567
114124
  return error51.issues.slice(0, 5).map((issue2) => `${issue2.path.join(".") || "arguments"}: ${issue2.message}`).join("; ");
113568
114125
  }
@@ -113579,109 +114136,9 @@ function resolveAccount(provider, allowed, requested) {
113579
114136
  if (candidates.length === 1) return candidates[0];
113580
114137
  throw new ToolInputError(`Pass account: this bot has more than one ${label} account (${candidates.map((account2) => account2.email).join(", ")}).`);
113581
114138
  }
113582
- function addresses(value, field) {
113583
- if (value === void 0) return [];
113584
- const list3 = (Array.isArray(value) ? value : value.split(",")).map((item) => item.trim()).filter(Boolean);
113585
- if (list3.length > 50) throw new ToolInputError(`${field}: at most 50 addresses`);
113586
- for (const item of list3) {
113587
- if (!EMAIL2.test(item)) throw new ToolInputError(`${field}: "${item.slice(0, 80)}" is not an email address`);
113588
- }
113589
- return list3;
113590
- }
113591
- var ProviderApiError = class extends Error {
113592
- status;
113593
- constructor(status, message4) {
113594
- super(message4);
113595
- this.status = status;
113596
- }
113597
- };
113598
- async function readLimited(response, limit) {
113599
- const declared = Number(response.headers.get("content-length") ?? "0");
113600
- if (declared > limit) {
113601
- await response.body?.cancel().catch(() => {
113602
- });
113603
- return null;
113604
- }
113605
- if (!response.body) return Buffer.alloc(0);
113606
- const reader = response.body.getReader();
113607
- const chunks = [];
113608
- let size = 0;
113609
- for (; ; ) {
113610
- const { done, value } = await reader.read();
113611
- if (done) break;
113612
- size += value.byteLength;
113613
- if (size > limit) {
113614
- await reader.cancel().catch(() => {
113615
- });
113616
- return null;
113617
- }
113618
- chunks.push(value);
113619
- }
113620
- return Buffer.concat(chunks);
113621
- }
113622
- function providerErrorMessage(body, status) {
113623
- const error51 = body?.error;
113624
- const message4 = typeof error51 === "string" ? error51 : error51 && typeof error51 === "object" && typeof error51.message === "string" ? error51.message : "";
113625
- return (message4 || `request failed with HTTP ${status}`).split(/\r?\n/)[0].slice(0, 300);
113626
- }
113627
- async function call(ctx, account2, url2, init) {
113628
- const fetcher = ctx.fetch ?? fetch;
113629
- const { expect, ...request4 } = init;
113630
- for (let attempt = 0; attempt < 2; attempt += 1) {
113631
- const token = await ctx.accessToken(account2.id);
113632
- const headers = new Headers(request4.headers);
113633
- headers.set("authorization", `Bearer ${token}`);
113634
- if (!headers.has("accept") && expect === "json") headers.set("accept", "application/json");
113635
- const response = await fetcher(url2, { ...request4, headers, signal: AbortSignal.timeout(HTTP_TIMEOUT_MS2) });
113636
- if (response.status === 401 && attempt === 0) {
113637
- await response.body?.cancel().catch(() => {
113638
- });
113639
- ctx.invalidate(account2.id);
113640
- continue;
113641
- }
113642
- if (!response.ok) {
113643
- const raw = await readLimited(response, 64 * 1024);
113644
- let body = null;
113645
- try {
113646
- body = raw ? JSON.parse(raw.toString("utf8")) : null;
113647
- } catch {
113648
- body = null;
113649
- }
113650
- const message4 = providerErrorMessage(body, response.status);
113651
- if (response.status === 403) throw new ProviderApiError(403, `${account2.email} does not allow this: ${message4}`);
113652
- if (response.status === 404) throw new ProviderApiError(404, `Not found in ${account2.email}: ${message4}`);
113653
- throw new ProviderApiError(response.status, `${OAUTH_PROVIDERS[account2.provider].label} refused the request for ${account2.email}: ${message4}`);
113654
- }
113655
- if (expect === "none") {
113656
- await response.body?.cancel().catch(() => {
113657
- });
113658
- return void 0;
113659
- }
113660
- const bytes2 = await readLimited(response, expect === "json" ? MAX_JSON_BYTES : MAX_DOWNLOAD_BYTES);
113661
- if (expect === "bytes") return bytes2;
113662
- if (!bytes2) throw new ProviderApiError(502, "The response was too large");
113663
- try {
113664
- return JSON.parse(bytes2.toString("utf8"));
113665
- } catch {
113666
- throw new ProviderApiError(502, "The service returned an unreadable response");
113667
- }
113668
- }
113669
- throw new ProviderApiError(401, `${account2.email} needs to sign in again: open Settings \u2192 Accounts and connect it again.`);
113670
- }
113671
- function parse7(schema5, value, what) {
113672
- const parsed = schema5.safeParse(value);
113673
- if (!parsed.success) throw new ProviderApiError(502, `Unexpected ${what} response`);
113674
- return parsed.data;
113675
- }
113676
- function json4(value) {
113677
- return JSON.stringify(value, null, 1);
113678
- }
113679
114139
  function decodeBase64Url(data) {
113680
114140
  return data ? Buffer.from(data, "base64url").toString("utf8") : "";
113681
114141
  }
113682
- function htmlToText(html) {
113683
- return html.replace(/<(script|style)[\s\S]*?<\/\1>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|tr|li|h\d)>/gi, "\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/\n{3,}/g, "\n\n").trim();
113684
- }
113685
114142
  function encodeHeader(value) {
113686
114143
  return /^[\x20-\x7e]*$/.test(value) ? value : `=?UTF-8?B?${Buffer.from(value, "utf8").toString("base64")}?=`;
113687
114144
  }
@@ -113714,7 +114171,6 @@ function readable(name2, mimeType) {
113714
114171
  return Boolean(officeKind(name2, mimeType)) || TEXT_MIME.test(mimeType) || TEXT_EXTENSION2.test(name2);
113715
114172
  }
113716
114173
  var GMAIL = "https://gmail.googleapis.com/gmail/v1/users/me";
113717
- var CALENDAR = "https://www.googleapis.com/calendar/v3";
113718
114174
  var DRIVE2 = "https://www.googleapis.com/drive/v3";
113719
114175
  var gmailPartSchema = external_exports.lazy(() => external_exports.object({
113720
114176
  mimeType: external_exports.string().optional(),
@@ -113803,67 +114259,6 @@ async function gmailSendDraft(ctx, account2, args) {
113803
114259
  );
113804
114260
  return json4({ account: account2.email, sent: true, messageId: sent.id, threadId: sent.threadId });
113805
114261
  }
113806
- var googleEventSchema = external_exports.object({
113807
- id: external_exports.string(),
113808
- summary: external_exports.string().optional(),
113809
- description: external_exports.string().optional(),
113810
- location: external_exports.string().optional(),
113811
- status: external_exports.string().optional(),
113812
- htmlLink: external_exports.string().optional(),
113813
- start: external_exports.object({ dateTime: external_exports.string().optional(), date: external_exports.string().optional(), timeZone: external_exports.string().optional() }).optional(),
113814
- end: external_exports.object({ dateTime: external_exports.string().optional(), date: external_exports.string().optional(), timeZone: external_exports.string().optional() }).optional(),
113815
- organizer: external_exports.object({ email: external_exports.string().optional() }).optional(),
113816
- attendees: external_exports.array(external_exports.object({ email: external_exports.string().optional(), responseStatus: external_exports.string().optional() })).optional()
113817
- });
113818
- function googleEvent(event) {
113819
- return {
113820
- id: event.id,
113821
- summary: event.summary,
113822
- start: event.start?.dateTime ?? event.start?.date,
113823
- end: event.end?.dateTime ?? event.end?.date,
113824
- location: event.location,
113825
- organizer: event.organizer?.email,
113826
- attendees: event.attendees?.map((attendee) => `${attendee.email ?? ""}${attendee.responseStatus ? ` (${attendee.responseStatus})` : ""}`),
113827
- description: event.description ? bounded2(event.description, 2e3) : void 0,
113828
- link: event.htmlLink
113829
- };
113830
- }
113831
- async function calendarListEvents(ctx, account2, args) {
113832
- const calendarId = encodeURIComponent(args.calendarId ?? "primary");
113833
- const query = new URLSearchParams({ timeMin: args.timeMin, timeMax: args.timeMax, singleEvents: "true", orderBy: "startTime", maxResults: String(args.max ?? 25) });
113834
- const list3 = parse7(external_exports.object({ items: external_exports.array(googleEventSchema).optional(), timeZone: external_exports.string().optional() }), await call(ctx, account2, `${CALENDAR}/calendars/${calendarId}/events?${query}`, { expect: "json" }), "Calendar");
113835
- return json4({ account: account2.email, timeZone: list3.timeZone, events: (list3.items ?? []).map(googleEvent) });
113836
- }
113837
- function eventTime(value, timeZone, field) {
113838
- if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return { allDay: true, date: value };
113839
- const hasOffset = /(?:Z|[+-]\d{2}:\d{2})$/.test(value);
113840
- if (!hasOffset && !timeZone) throw new ToolInputError(`${field}: add a UTC offset (e.g. 2026-10-01T15:00:00-07:00) or pass timeZone`);
113841
- return { allDay: false, dateTime: value, hasOffset };
113842
- }
113843
- async function calendarCreateEvent(ctx, account2, args) {
113844
- const start = eventTime(args.start, args.timeZone, "start");
113845
- const end = eventTime(args.end, args.timeZone, "end");
113846
- if (start.allDay !== end.allDay) throw new ToolInputError("start and end must both be dates or both be date-times");
113847
- const attendees = addresses(args.attendees, "attendees");
113848
- const time4 = (value) => value.allDay ? { date: value.date } : { dateTime: value.dateTime, ...args.timeZone ? { timeZone: args.timeZone } : {} };
113849
- const body = {
113850
- summary: args.summary,
113851
- ...args.description ? { description: args.description } : {},
113852
- ...args.location ? { location: args.location } : {},
113853
- start: time4(start),
113854
- end: time4(end),
113855
- ...attendees.length ? { attendees: attendees.map((email3) => ({ email: email3 })) } : {}
113856
- };
113857
- const calendarId = encodeURIComponent(args.calendarId ?? "primary");
113858
- const query = new URLSearchParams({ sendUpdates: attendees.length ? "all" : "none" });
113859
- const created = parse7(googleEventSchema, await call(ctx, account2, `${CALENDAR}/calendars/${calendarId}/events?${query}`, {
113860
- method: "POST",
113861
- headers: { "content-type": "application/json" },
113862
- body: JSON.stringify(body),
113863
- expect: "json"
113864
- }), "Calendar");
113865
- return json4({ account: account2.email, created: googleEvent(created) });
113866
- }
113867
114262
  var driveFileSchema = external_exports.object({
113868
114263
  id: external_exports.string(),
113869
114264
  name: external_exports.string().optional(),
@@ -113908,8 +114303,6 @@ async function driveRead(ctx, account2, args) {
113908
114303
  const text17 = bytes2 ? exportType ? bytes2.toString("utf8") : fileText(file2.name ?? "", mimeType, bytes2) : null;
113909
114304
  return json4(text17 === null ? { ...details, note: "This file's text cannot be read here; share the link instead." } : { ...details, text: bounded2(text17, MAX_FILE_TEXT_CHARS) });
113910
114305
  }
113911
- var GRAPH = "https://graph.microsoft.com/v1.0";
113912
- var graphRecipient = external_exports.object({ emailAddress: external_exports.object({ address: external_exports.string().optional(), name: external_exports.string().optional() }).optional() });
113913
114306
  var graphMessageSchema = external_exports.object({
113914
114307
  id: external_exports.string(),
113915
114308
  conversationId: external_exports.string().optional(),
@@ -113923,11 +114316,6 @@ var graphMessageSchema = external_exports.object({
113923
114316
  hasAttachments: external_exports.boolean().optional(),
113924
114317
  body: external_exports.object({ contentType: external_exports.string().optional(), content: external_exports.string().optional() }).optional()
113925
114318
  });
113926
- function recipient(value) {
113927
- const address2 = value?.emailAddress?.address;
113928
- const name2 = value?.emailAddress?.name;
113929
- return address2 ? name2 && name2 !== address2 ? `${name2} <${address2}>` : address2 : void 0;
113930
- }
113931
114319
  async function outlookSearch(ctx, account2, args) {
113932
114320
  const query = new URLSearchParams({
113933
114321
  $search: `"${args.q.replace(/["\\]/g, " ")}"`,
@@ -113990,78 +114378,6 @@ async function outlookSendDraft(ctx, account2, args) {
113990
114378
  await call(ctx, account2, `${GRAPH}/me/messages/${encodeURIComponent(args.draftId)}/send`, { method: "POST", expect: "none" });
113991
114379
  return json4({ account: account2.email, sent: true, draftId: args.draftId });
113992
114380
  }
113993
- var graphTime = external_exports.object({ dateTime: external_exports.string().optional(), timeZone: external_exports.string().optional() });
113994
- var graphEventSchema = external_exports.object({
113995
- id: external_exports.string(),
113996
- subject: external_exports.string().nullable().optional(),
113997
- start: graphTime.optional(),
113998
- end: graphTime.optional(),
113999
- isAllDay: external_exports.boolean().optional(),
114000
- location: external_exports.object({ displayName: external_exports.string().optional() }).nullable().optional(),
114001
- organizer: graphRecipient.nullable().optional(),
114002
- attendees: external_exports.array(graphRecipient.extend({ status: external_exports.object({ response: external_exports.string().optional() }).optional() })).optional(),
114003
- webLink: external_exports.string().optional(),
114004
- bodyPreview: external_exports.string().optional()
114005
- });
114006
- function graphEvent(event) {
114007
- return {
114008
- id: event.id,
114009
- summary: event.subject,
114010
- start: event.start?.dateTime ? `${event.start.dateTime}${event.start.timeZone === "UTC" ? "Z" : ` (${event.start.timeZone ?? ""})`}` : void 0,
114011
- end: event.end?.dateTime ? `${event.end.dateTime}${event.end.timeZone === "UTC" ? "Z" : ` (${event.end.timeZone ?? ""})`}` : void 0,
114012
- allDay: event.isAllDay,
114013
- location: event.location?.displayName || void 0,
114014
- organizer: recipient(event.organizer),
114015
- attendees: event.attendees?.map((attendee) => `${recipient(attendee) ?? ""}${attendee.status?.response ? ` (${attendee.status.response})` : ""}`),
114016
- preview: event.bodyPreview ? bounded2(event.bodyPreview, 1e3) : void 0,
114017
- link: event.webLink
114018
- };
114019
- }
114020
- async function outlookListEvents(ctx, account2, args) {
114021
- const query = new URLSearchParams({
114022
- startDateTime: new Date(args.timeMin).toISOString(),
114023
- endDateTime: new Date(args.timeMax).toISOString(),
114024
- $top: String(args.max ?? 25),
114025
- $orderby: "start/dateTime",
114026
- $select: "id,subject,start,end,isAllDay,location,organizer,attendees,webLink,bodyPreview"
114027
- });
114028
- const list3 = parse7(external_exports.object({ value: external_exports.array(graphEventSchema) }), await call(ctx, account2, `${GRAPH}/me/calendarView?${query}`, {
114029
- headers: { prefer: 'outlook.timezone="UTC"' },
114030
- expect: "json"
114031
- }), "Outlook calendar");
114032
- return json4({ account: account2.email, timeZone: "UTC", events: list3.value.map(graphEvent) });
114033
- }
114034
- function graphDateTime(value, timeZone, field) {
114035
- if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return { dateTime: `${value}T00:00:00`, timeZone: timeZone ?? "UTC", allDay: true };
114036
- if (/(?:Z|[+-]\d{2}:\d{2})$/.test(value)) {
114037
- const parsed = Date.parse(value);
114038
- if (!Number.isFinite(parsed)) throw new ToolInputError(`${field}: not a valid date-time`);
114039
- return { dateTime: new Date(parsed).toISOString().replace(/\.\d{3}Z$/, ""), timeZone: "UTC", allDay: false };
114040
- }
114041
- if (!timeZone) throw new ToolInputError(`${field}: add a UTC offset (e.g. 2026-10-01T15:00:00-07:00) or pass timeZone`);
114042
- return { dateTime: value, timeZone, allDay: false };
114043
- }
114044
- async function outlookCreateEvent(ctx, account2, args) {
114045
- const start = graphDateTime(args.start, args.timeZone, "start");
114046
- const end = graphDateTime(args.end, args.timeZone, "end");
114047
- if (start.allDay !== end.allDay) throw new ToolInputError("start and end must both be dates or both be date-times");
114048
- const attendees = addresses(args.attendees, "attendees");
114049
- const created = parse7(graphEventSchema, await call(ctx, account2, `${GRAPH}/me/events`, {
114050
- method: "POST",
114051
- headers: { "content-type": "application/json", prefer: 'outlook.timezone="UTC"' },
114052
- body: JSON.stringify({
114053
- subject: args.summary,
114054
- ...args.description ? { body: { contentType: "Text", content: args.description } } : {},
114055
- start: { dateTime: start.dateTime, timeZone: start.timeZone },
114056
- end: { dateTime: end.dateTime, timeZone: end.timeZone },
114057
- ...start.allDay ? { isAllDay: true } : {},
114058
- ...args.location ? { location: { displayName: args.location } } : {},
114059
- ...attendees.length ? { attendees: attendees.map((address2) => ({ emailAddress: { address: address2 }, type: "required" })) } : {}
114060
- }),
114061
- expect: "json"
114062
- }), "Outlook calendar");
114063
- return json4({ account: account2.email, created: graphEvent(created) });
114064
- }
114065
114381
  var driveItemSchema = external_exports.object({
114066
114382
  id: external_exports.string(),
114067
114383
  name: external_exports.string().optional(),
@@ -114098,16 +114414,13 @@ var RUNNERS = {
114098
114414
  gmail_read: gmailRead,
114099
114415
  gmail_create_draft: gmailCreateDraft,
114100
114416
  gmail_send_draft: gmailSendDraft,
114101
- calendar_list_events: calendarListEvents,
114102
- calendar_create_event: calendarCreateEvent,
114417
+ ...CALENDAR_RUNNERS,
114103
114418
  drive_search: driveSearch,
114104
114419
  drive_read: driveRead,
114105
114420
  outlook_search: outlookSearch,
114106
114421
  outlook_read: outlookRead,
114107
114422
  outlook_create_draft: outlookCreateDraft,
114108
114423
  outlook_send_draft: outlookSendDraft,
114109
- outlook_calendar_list_events: outlookListEvents,
114110
- outlook_calendar_create_event: outlookCreateEvent,
114111
114424
  onedrive_search: onedriveSearch,
114112
114425
  onedrive_read: onedriveRead
114113
114426
  };
@@ -121539,6 +121852,11 @@ function checkCleanup(input, output) {
121539
121852
  const kept = new Set(contentTokens(cleaned));
121540
121853
  if (tokens.filter((t) => kept.has(t)).length / tokens.length < 0.6) return { ok: false, reason: "overlap" };
121541
121854
  }
121855
+ const spoken2 = new Set(contentTokens(input));
121856
+ const written = new Set(contentTokens(cleaned));
121857
+ const added = [...written].filter((t) => !spoken2.has(t)).length;
121858
+ const removed = [...spoken2].filter((t) => !written.has(t)).length;
121859
+ if (added > removed + 1) return { ok: false, reason: "added" };
121542
121860
  return { ok: true, text: cleaned };
121543
121861
  }
121544
121862
  async function ask(provider, prompt, timeoutMs) {