ask-marcel-office-cli 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -13916,8 +13916,41 @@ var init_zod = __esm(() => {
13916
13916
  init_external();
13917
13917
  });
13918
13918
 
13919
+ // src/use-cases/commands/reject-unknown-params.ts
13920
+ var camelToKebab = (value) => value.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`), allowedKeys = (schema) => {
13921
+ if (!(schema instanceof exports_external.ZodObject))
13922
+ return [];
13923
+ return Object.keys(schema.shape);
13924
+ }, unknownParamError = (unknown2, allowed) => {
13925
+ const named = unknown2.map((k) => `--${camelToKebab(k)}`).join(", ");
13926
+ const supported = allowed.map((k) => `--${camelToKebab(k)}`).toSorted((a, b) => a.localeCompare(b)).join(", ");
13927
+ return {
13928
+ type: "validation_error",
13929
+ code: "unknown_parameter",
13930
+ message: `${named} ${unknown2.length === 1 ? "is not a parameter" : "are not parameters"} of this command, so it would have been ignored rather than applied. Supported: ${supported || "(none)"}.`
13931
+ };
13932
+ }, rejectUnknownParams = (schema, params) => {
13933
+ const allowed = allowedKeys(schema);
13934
+ if (allowed.length === 0)
13935
+ return;
13936
+ const unknown2 = Object.keys(params).filter((key) => !allowed.includes(key));
13937
+ if (unknown2.length === 0)
13938
+ return;
13939
+ return err(unknownParamError(unknown2, allowed));
13940
+ }, withUnknownParamRejection = (command) => {
13941
+ const { executeLocal } = command;
13942
+ return {
13943
+ ...command,
13944
+ execute: async (graph, params) => rejectUnknownParams(command.schema, params) ?? await command.execute(graph, params),
13945
+ ...executeLocal === undefined ? {} : { executeLocal: async (fs, params) => rejectUnknownParams(command.schema, params) ?? await executeLocal(fs, params) }
13946
+ };
13947
+ };
13948
+ var init_reject_unknown_params = __esm(() => {
13949
+ init_zod();
13950
+ });
13951
+
13919
13952
  // src/use-cases/commands/format-zod-error.ts
13920
- var camelToKebab = (s) => s.replaceAll(/([A-Z])/g, "-$1").toLowerCase(), humanize = (issue2) => {
13953
+ var camelToKebab2 = (s) => s.replaceAll(/([A-Z])/g, "-$1").toLowerCase(), humanize = (issue2) => {
13921
13954
  if (issue2.code === "invalid_type")
13922
13955
  return "is missing";
13923
13956
  if (issue2.code === "too_small") {
@@ -13933,7 +13966,7 @@ var camelToKebab = (s) => s.replaceAll(/([A-Z])/g, "-$1").toLowerCase(), humaniz
13933
13966
  if (issue2.path.length === 0)
13934
13967
  return `<root>: ${issue2.message}`;
13935
13968
  const path = renderPath(issue2.path);
13936
- const flag = `--${camelToKebab(path)}`;
13969
+ const flag = `--${camelToKebab2(path)}`;
13937
13970
  return `${flag} ${humanize(issue2)}`;
13938
13971
  }).join("; ");
13939
13972
  };
@@ -16652,7 +16685,6 @@ var init_download_drive_item_content = __esm(() => {
16652
16685
  meta8 = {
16653
16686
  summary: 'Download the binary content of a file stored in OneDrive / SharePoint, with the bytes inlined. The CLI follows the Graph 302 → SharePoint media-transform redirect internally so the LLM never has to fetch an external URL. The bytes are CONTENT-SNIFFED, not judged by extension: if they decode as valid UTF-8 they come back as `{contentType: "text/plain", size, text}` (avoids ~33% base64 bloat, works for any text file regardless of name); otherwise as `{contentType, size, base64}`. A binary file that happens to be named `.txt` is returned faithfully as base64 — never silently corrupted into `�` by a forced text decode.',
16654
16687
  category: "drive",
16655
- commandAliases: ["download-onedrive-file-content"],
16656
16688
  graphMethod: "GET",
16657
16689
  graphPathTemplate: "/drives/{drive-id}/items/{item-id}/content",
16658
16690
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/api/driveitem-get-content",
@@ -16922,7 +16954,6 @@ var init_get_calendar_event = __esm(() => {
16922
16954
  name: "event-id",
16923
16955
  key: "eventId",
16924
16956
  required: true,
16925
- aliases: [{ name: "id", key: "id" }],
16926
16957
  description: "Microsoft Graph event ID. Returned by `ask-marcel-office list-calendar-events` in the `id` field of each event."
16927
16958
  },
16928
16959
  ...selectExpandOptions
@@ -17104,8 +17135,8 @@ var init_get_calendar_view = __esm(() => {
17104
17135
  graphPathTemplate: "/me/calendarView?startDateTime={start-date-time}&endDateTime={end-date-time}",
17105
17136
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/api/user-list-calendarview",
17106
17137
  options: [
17107
- { name: "start-date-time", key: "startDateTime", required: true, aliases: [{ name: "start", key: "start" }], description: `Lower bound. ${RELATIVE_DATE_DESCRIPTION}` },
17108
- { name: "end-date-time", key: "endDateTime", required: true, aliases: [{ name: "end", key: "end" }], description: `Upper bound. ${RELATIVE_DATE_DESCRIPTION}` },
17138
+ { name: "start-date-time", key: "startDateTime", required: true, description: `Lower bound. ${RELATIVE_DATE_DESCRIPTION}` },
17139
+ { name: "end-date-time", key: "endDateTime", required: true, description: `Upper bound. ${RELATIVE_DATE_DESCRIPTION}` },
17109
17140
  ...odataQueryOptions
17110
17141
  ],
17111
17142
  example: "ask-marcel-office list-calendar-view --start-date-time 'start-of-week' --end-date-time 'end-of-week'",
@@ -17152,7 +17183,7 @@ var init_get_drive_delta = __esm(() => {
17152
17183
  init_build_command();
17153
17184
  init_odata_query();
17154
17185
  baseSchema4 = exports_external.object({ driveId: exports_external.string().min(1), itemId: exports_external.string().min(1) });
17155
- ({ execute: execute10, schema: schema10 } = buildNoSkipListCommand((p) => `/drives/${p.driveId}/items/${p.itemId}/delta()`, baseSchema4));
17186
+ ({ execute: execute10, schema: schema10 } = buildPickODataListCommand((p) => `/drives/${p.driveId}/items/${p.itemId}/delta()`, baseSchema4, ["top", "select", "expand"]));
17156
17187
  meta12 = {
17157
17188
  summary: "Get the incremental change set (added / modified / deleted items) under a OneDrive / SharePoint folder. Use the `@odata.deltaLink` from a previous response to resume.",
17158
17189
  category: "drive",
@@ -17170,10 +17201,9 @@ var init_get_drive_delta = __esm(() => {
17170
17201
  name: "item-id",
17171
17202
  key: "itemId",
17172
17203
  required: true,
17173
- description: "driveItem ID of the folder whose subtree to track. Use the root folder ID from `get-drive-root-item` to track the entire drive. Accepts `--folder-id` as an alias for parity with `list-folder-files` (same concept, same flag name).",
17174
- aliases: [{ name: "folder-id", key: "folderId" }]
17204
+ description: "driveItem ID of the folder whose subtree to track. Use the root folder ID from `get-drive-root-item` to track the entire drive."
17175
17205
  },
17176
- ...noSkipOptions
17206
+ ...pickODataOptions(["top", "select", "expand"])
17177
17207
  ],
17178
17208
  example: "ask-marcel-office get-drive-delta --drive-id 'b!1234' --item-id '01ROOT'",
17179
17209
  responseShape: "collection of changed Microsoft Graph `driveItem` resources under `data.value[]`. Cursor tokens are hoisted to envelope level: top-level `nextLink` while paging, then top-level `deltaLink` on the final page.",
@@ -17244,7 +17274,6 @@ var init_get_drive_root_item = __esm(() => {
17244
17274
  name: "drive-id",
17245
17275
  key: "driveId",
17246
17276
  required: true,
17247
- aliases: [{ name: "id", key: "id" }],
17248
17277
  description: DRIVE_ID_DESCRIPTION
17249
17278
  },
17250
17279
  ...selectExpandOptions
@@ -17530,8 +17559,7 @@ var init_get_mail_message = __esm(() => {
17530
17559
  name: "message-id",
17531
17560
  key: "messageId",
17532
17561
  required: true,
17533
- aliases: [{ name: "id", key: "id" }],
17534
- description: "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
17562
+ description: "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`."
17535
17563
  },
17536
17564
  ...selectExpandOptions
17537
17565
  ],
@@ -17725,8 +17753,7 @@ var init_convert_mail_to_markdown = __esm(() => {
17725
17753
  name: "message-id",
17726
17754
  key: "messageId",
17727
17755
  required: true,
17728
- aliases: [{ name: "id", key: "id" }],
17729
- description: "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
17756
+ description: "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`."
17730
17757
  },
17731
17758
  {
17732
17759
  name: "inline-images",
@@ -17872,8 +17899,7 @@ var init_get_mail_signature = __esm(() => {
17872
17899
  name: "message-id",
17873
17900
  key: "messageId",
17874
17901
  required: false,
17875
- aliases: [{ name: "id", key: "id" }],
17876
- description: "Read the signature from THIS message instead of scanning the sent folder. Use when the scan finds nothing (the message was composed in Outlook desktop) or to pin a specific signature. Source from list-mail-folder-messages --mail-folder-id sentitems. Accepts `--id` as an alias.",
17902
+ description: "Read the signature from THIS message instead of scanning the sent folder. Use when the scan finds nothing (the message was composed in Outlook desktop) or to pin a specific signature. Source from list-mail-folder-messages --mail-folder-id sentitems.",
17877
17903
  argumentHint: { kind: "idOrName" }
17878
17904
  }
17879
17905
  ],
@@ -18143,11 +18169,7 @@ var init_get_onenote_page_as_markdown = __esm(() => {
18143
18169
  name: "onenote-page-id",
18144
18170
  key: "onenotePageId",
18145
18171
  required: true,
18146
- description: "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`.",
18147
- aliases: [
18148
- { name: "id", key: "id" },
18149
- { name: "page-id", key: "pageId" }
18150
- ]
18172
+ description: "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
18151
18173
  },
18152
18174
  {
18153
18175
  name: "inline-images",
@@ -18198,11 +18220,7 @@ var init_get_onenote_page_content = __esm(() => {
18198
18220
  name: "onenote-page-id",
18199
18221
  key: "onenotePageId",
18200
18222
  required: true,
18201
- description: "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`.",
18202
- aliases: [
18203
- { name: "id", key: "id" },
18204
- { name: "page-id", key: "pageId" }
18205
- ]
18223
+ description: "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
18206
18224
  }
18207
18225
  ],
18208
18226
  example: "ask-marcel-office get-onenote-page-content --onenote-page-id '1-abc...'",
@@ -18235,11 +18253,7 @@ var init_get_planner_bucket = __esm(() => {
18235
18253
  name: "planner-bucket-id",
18236
18254
  key: "plannerBucketId",
18237
18255
  required: true,
18238
- description: "Planner bucket ID. Returned by `ask-marcel-office list-plan-buckets`.",
18239
- aliases: [
18240
- { name: "id", key: "id" },
18241
- { name: "bucket-id", key: "bucketId" }
18242
- ]
18256
+ description: "Planner bucket ID. Returned by `ask-marcel-office list-plan-buckets`."
18243
18257
  }
18244
18258
  ],
18245
18259
  example: "ask-marcel-office get-planner-bucket --planner-bucket-id 'sFNeQRFu_kqhxpwwAhmA15gAGfoT'",
@@ -18271,11 +18285,7 @@ var init_get_planner_plan = __esm(() => {
18271
18285
  name: "planner-plan-id",
18272
18286
  key: "plannerPlanId",
18273
18287
  required: true,
18274
- description: "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`.",
18275
- aliases: [
18276
- { name: "id", key: "id" },
18277
- { name: "plan-id", key: "planId" }
18278
- ]
18288
+ description: "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
18279
18289
  }
18280
18290
  ],
18281
18291
  example: "ask-marcel-office get-planner-plan --planner-plan-id 'xqQg5FS2LkCp935s-FIFm5gAB6'",
@@ -18307,11 +18317,7 @@ var init_get_planner_task_details = __esm(() => {
18307
18317
  name: "planner-task-id",
18308
18318
  key: "plannerTaskId",
18309
18319
  required: true,
18310
- description: "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`. Accepts `--task-id` as a shorter alias (each task command targets exactly one of Planner or To Do, so within this command's flag set there is no ambiguity).",
18311
- aliases: [
18312
- { name: "id", key: "id" },
18313
- { name: "task-id", key: "taskId" }
18314
- ]
18320
+ description: "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`."
18315
18321
  }
18316
18322
  ],
18317
18323
  example: "ask-marcel-office get-planner-task-details --planner-task-id '01tx7Ic7-USXEwt0lvR1cmgAH8gK'",
@@ -18343,11 +18349,7 @@ var init_get_planner_task = __esm(() => {
18343
18349
  name: "planner-task-id",
18344
18350
  key: "plannerTaskId",
18345
18351
  required: true,
18346
- description: "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`. Accepts `--task-id` as a shorter alias (each task command targets exactly one of Planner or To Do, so within this command's flag set there is no ambiguity).",
18347
- aliases: [
18348
- { name: "id", key: "id" },
18349
- { name: "task-id", key: "taskId" }
18350
- ]
18352
+ description: "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`."
18351
18353
  }
18352
18354
  ],
18353
18355
  example: "ask-marcel-office get-planner-task --planner-task-id '01tx7Ic7-USXEwt0lvR1cmgAH8gK'",
@@ -18459,8 +18461,7 @@ var init_get_sharepoint_site_list_item = __esm(() => {
18459
18461
  name: "list-item-id",
18460
18462
  key: "listItemId",
18461
18463
  required: true,
18462
- description: "listItem ID (typically a small integer). Returned by `ask-marcel-office list-sharepoint-site-list-items`.",
18463
- aliases: [{ name: "item-id", key: "itemId" }]
18464
+ description: "listItem ID (typically a small integer). Returned by `ask-marcel-office list-sharepoint-site-list-items`."
18464
18465
  },
18465
18466
  ...selectExpandOptions
18466
18467
  ],
@@ -18530,7 +18531,6 @@ var init_get_sharepoint_site = __esm(() => {
18530
18531
  name: "site-id",
18531
18532
  key: "siteId",
18532
18533
  required: true,
18533
- aliases: [{ name: "id", key: "id" }],
18534
18534
  description: "SharePoint site ID. Either the composite ID (`hostname,site-collection-id,site-id`) returned by `ask-marcel-office search-sharepoint-sites-by-name`, or the literal `root` to refer to the tenant root site."
18535
18535
  },
18536
18536
  ...selectExpandOptions
@@ -18587,21 +18587,18 @@ var init_get_schedule = __esm(() => {
18587
18587
  name: "schedules",
18588
18588
  key: "schedules",
18589
18589
  required: true,
18590
- aliases: [{ name: "emails", key: "emails" }],
18591
18590
  description: "Comma-separated SMTP addresses of the users and/or room resources to check (e.g. `alice@contoso.com,bob@contoso.com,room-4a@contoso.com`). Resolve names to addresses first via `list-relevant-people` or `microsoft-search-query`."
18592
18591
  },
18593
18592
  {
18594
18593
  name: "start-date-time",
18595
18594
  key: "startDateTime",
18596
18595
  required: true,
18597
- aliases: [{ name: "start", key: "start" }],
18598
18596
  description: `Window lower bound (interpreted as UTC). ${RELATIVE_DATE_DESCRIPTION}`
18599
18597
  },
18600
18598
  {
18601
18599
  name: "end-date-time",
18602
18600
  key: "endDateTime",
18603
18601
  required: true,
18604
- aliases: [{ name: "end", key: "end" }],
18605
18602
  description: `Window upper bound (interpreted as UTC). Graph caps the span at 62 days. ${RELATIVE_DATE_DESCRIPTION}`
18606
18603
  },
18607
18604
  {
@@ -18689,11 +18686,10 @@ var init_get_specific_calendar_view = __esm(() => {
18689
18686
  name: "calendar-id",
18690
18687
  key: "calendarId",
18691
18688
  required: true,
18692
- aliases: [{ name: "id", key: "id" }],
18693
18689
  description: "Calendar ID, or `primary` / `default` for the signed-in user’s default calendar. Returned by `ask-marcel-office list-calendars`."
18694
18690
  },
18695
- { name: "start-date-time", key: "startDateTime", required: true, aliases: [{ name: "start", key: "start" }], description: `Lower bound. ${RELATIVE_DATE_DESCRIPTION}` },
18696
- { name: "end-date-time", key: "endDateTime", required: true, aliases: [{ name: "end", key: "end" }], description: `Upper bound. ${RELATIVE_DATE_DESCRIPTION}` },
18691
+ { name: "start-date-time", key: "startDateTime", required: true, description: `Lower bound. ${RELATIVE_DATE_DESCRIPTION}` },
18692
+ { name: "end-date-time", key: "endDateTime", required: true, description: `Upper bound. ${RELATIVE_DATE_DESCRIPTION}` },
18697
18693
  ...odataQueryOptions
18698
18694
  ],
18699
18695
  example: "ask-marcel-office list-specific-calendar-view --calendar-id 'primary' --start-date-time '2026-04-01T00:00:00Z' --end-date-time '2026-05-01T00:00:00Z'",
@@ -18771,7 +18767,6 @@ var init_get_team = __esm(() => {
18771
18767
  name: "team-id",
18772
18768
  key: "teamId",
18773
18769
  required: true,
18774
- aliases: [{ name: "id", key: "id" }],
18775
18770
  description: "Microsoft Teams team ID. Returned by `ask-marcel-office list-joined-teams`."
18776
18771
  },
18777
18772
  ...selectExpandOptions
@@ -18838,18 +18833,13 @@ var init_get_todo_task = __esm(() => {
18838
18833
  name: "todo-task-list-id",
18839
18834
  key: "todoTaskListId",
18840
18835
  required: true,
18841
- description: "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`.",
18842
- aliases: [
18843
- { name: "task-list-id", key: "taskListId" },
18844
- { name: "todo-list-id", key: "todoListId" }
18845
- ]
18836
+ description: "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
18846
18837
  },
18847
18838
  {
18848
18839
  name: "todo-task-id",
18849
18840
  key: "todoTaskId",
18850
18841
  required: true,
18851
- description: "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`. Accepts `--task-id` as a shorter alias (within this command's flag set the To Do context is unambiguous).",
18852
- aliases: [{ name: "task-id", key: "taskId" }]
18842
+ description: "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`."
18853
18843
  },
18854
18844
  ...selectExpandOptions
18855
18845
  ],
@@ -18940,11 +18930,10 @@ var init_list_calendar_event_instances = __esm(() => {
18940
18930
  name: "event-id",
18941
18931
  key: "eventId",
18942
18932
  required: true,
18943
- aliases: [{ name: "id", key: "id" }],
18944
18933
  description: "Recurring event ID. Returned by `ask-marcel-office list-specific-calendar-events`."
18945
18934
  },
18946
- { name: "start-date-time", key: "startDateTime", required: true, aliases: [{ name: "start", key: "start" }], description: `Lower bound. ${RELATIVE_DATE_DESCRIPTION}` },
18947
- { name: "end-date-time", key: "endDateTime", required: true, aliases: [{ name: "end", key: "end" }], description: `Upper bound. ${RELATIVE_DATE_DESCRIPTION}` },
18935
+ { name: "start-date-time", key: "startDateTime", required: true, description: `Lower bound. ${RELATIVE_DATE_DESCRIPTION}` },
18936
+ { name: "end-date-time", key: "endDateTime", required: true, description: `Upper bound. ${RELATIVE_DATE_DESCRIPTION}` },
18948
18937
  ...odataQueryOptions
18949
18938
  ],
18950
18939
  example: "ask-marcel-office list-calendar-event-instances --calendar-id 'AAMkAGI2THVS...' --event-id 'AAMkABC...' --start-date-time '2026-04-01T00:00:00Z' --end-date-time '2026-05-01T00:00:00Z'",
@@ -19063,14 +19052,12 @@ var init_list_calendar_view_delta = __esm(() => {
19063
19052
  name: "start-date-time",
19064
19053
  key: "startDateTime",
19065
19054
  required: true,
19066
- aliases: [{ name: "start", key: "start" }],
19067
19055
  description: `Lower bound (required on the first call only — the deltaLink token encodes it for resumes). ${RELATIVE_DATE_DESCRIPTION}`
19068
19056
  },
19069
19057
  {
19070
19058
  name: "end-date-time",
19071
19059
  key: "endDateTime",
19072
19060
  required: true,
19073
- aliases: [{ name: "end", key: "end" }],
19074
19061
  description: `Upper bound (required on the first call only — the deltaLink token encodes it for resumes). ${RELATIVE_DATE_DESCRIPTION}`
19075
19062
  },
19076
19063
  ...topOnlyOptions
@@ -19150,7 +19137,6 @@ var init_list_chat_members = __esm(() => {
19150
19137
  name: "chat-id",
19151
19138
  key: "chatId",
19152
19139
  required: true,
19153
- aliases: [{ name: "id", key: "id" }],
19154
19140
  description: "Microsoft Teams chat ID, e.g. `19:abc...@thread.v2`. " + "Source the ID via `ask-marcel-office list-chats` (returns chat metadata for the signed-in user). " + "Alternative sources outside the CLI: the Teams desktop / web client (Open in browser → URL contains the chat thread ID), Microsoft Graph Explorer, " + "or URL-decode the `19%3ameeting_...%40thread.v2` segment of an `onlineMeeting.joinUrl` from `list-calendar-events`."
19155
19141
  },
19156
19142
  ...pickODataOptions(CHAT_MEMBERS_ODATA_KEYS)
@@ -19424,8 +19410,7 @@ var init_list_folder_files = __esm(() => {
19424
19410
  name: "item-id",
19425
19411
  key: "itemId",
19426
19412
  required: true,
19427
- description: 'driveItem ID of the folder (Graph identifies folders as driveItems too — there is no separate folder type). Use the root folder ID from `ask-marcel-office get-drive-root-item` to list the top of a drive. Accepts `--folder-id` as an alias since the command name implies "folder".',
19428
- aliases: [{ name: "folder-id", key: "folderId" }]
19413
+ description: "driveItem ID of the folder (Graph identifies folders as driveItems too — there is no separate folder type). Use the root folder ID from `ask-marcel-office get-drive-root-item` to list the top of a drive."
19429
19414
  },
19430
19415
  ...noSkipOptions,
19431
19416
  TENANT_ID_OPTION
@@ -19516,12 +19501,7 @@ var init_list_incomplete_todo_tasks = __esm(() => {
19516
19501
  name: "todo-task-list-id",
19517
19502
  key: "todoTaskListId",
19518
19503
  required: true,
19519
- description: "todoTaskList ID. Returned by `ask-marcel-office list-todo-task-lists`. The well-known name `tasks` (the default list) is accepted on this incomplete-tasks endpoint specifically — sibling commands like `list-todo-tasks` and `list-todo-tasks-delta` only accept resolved IDs. There is no Graph endpoint that returns incomplete tasks across every list — call this once per list.",
19520
- aliases: [
19521
- { name: "id", key: "id" },
19522
- { name: "task-list-id", key: "taskListId" },
19523
- { name: "todo-list-id", key: "todoListId" }
19524
- ]
19504
+ description: "todoTaskList ID. Returned by `ask-marcel-office list-todo-task-lists`. The well-known name `tasks` (the default list) is accepted on this incomplete-tasks endpoint specifically — sibling commands like `list-todo-tasks` and `list-todo-tasks-delta` only accept resolved IDs. There is no Graph endpoint that returns incomplete tasks across every list — call this once per list."
19525
19505
  },
19526
19506
  ...odataQueryOptions
19527
19507
  ],
@@ -19588,8 +19568,7 @@ var init_list_mail_attachments = __esm(() => {
19588
19568
  name: "message-id",
19589
19569
  key: "messageId",
19590
19570
  required: true,
19591
- aliases: [{ name: "id", key: "id" }],
19592
- description: "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
19571
+ description: "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`."
19593
19572
  },
19594
19573
  ...odataQueryOptions
19595
19574
  ],
@@ -19624,7 +19603,6 @@ var init_list_mail_child_folders = __esm(() => {
19624
19603
  name: "mail-folder-id",
19625
19604
  key: "mailFolderId",
19626
19605
  required: true,
19627
- aliases: [{ name: "id", key: "id" }],
19628
19606
  description: "mailFolder ID. Returned by `ask-marcel-office list-mail-folders`. Well-known names also work, e.g. `inbox`, `sentitems`, `drafts`."
19629
19607
  },
19630
19608
  ...odataQueryOptions
@@ -19660,7 +19638,6 @@ var init_list_mail_folder_messages = __esm(() => {
19660
19638
  name: "mail-folder-id",
19661
19639
  key: "mailFolderId",
19662
19640
  required: true,
19663
- aliases: [{ name: "id", key: "id" }],
19664
19641
  description: "mailFolder ID. Returned by `ask-marcel-office list-mail-folders`. Well-known names also work, e.g. `inbox`, `sentitems`, `drafts`. When listing `drafts`, a `conversationId` `$filter` is not a reliable check for whether a draft already exists on a thread: reply and forward drafts can split across several conversationIds, and `$filter` on Drafts is not read-your-writes consistent. Match client-side on subject and recipients instead, or use the `find-mail-drafts` command, which does exactly that."
19665
19642
  },
19666
19643
  ...odataQueryOptions
@@ -19782,7 +19759,6 @@ var init_list_onenote_notebook_sections = __esm(() => {
19782
19759
  name: "notebook-id",
19783
19760
  key: "notebookId",
19784
19761
  required: true,
19785
- aliases: [{ name: "id", key: "id" }],
19786
19762
  description: "OneNote notebook ID. Returned by `ask-marcel-office list-onenote-notebooks`."
19787
19763
  },
19788
19764
  ...odataQueryOptions
@@ -19845,11 +19821,7 @@ var init_list_onenote_section_pages = __esm(() => {
19845
19821
  name: "onenote-section-id",
19846
19822
  key: "onenoteSectionId",
19847
19823
  required: true,
19848
- description: "OneNote section ID. Returned by `ask-marcel-office list-onenote-notebook-sections` or `list-all-onenote-sections`.",
19849
- aliases: [
19850
- { name: "id", key: "id" },
19851
- { name: "section-id", key: "sectionId" }
19852
- ]
19824
+ description: "OneNote section ID. Returned by `ask-marcel-office list-onenote-notebook-sections` or `list-all-onenote-sections`."
19853
19825
  },
19854
19826
  ...odataQueryOptions
19855
19827
  ],
@@ -19884,11 +19856,7 @@ var init_list_plan_buckets = __esm(() => {
19884
19856
  name: "planner-plan-id",
19885
19857
  key: "plannerPlanId",
19886
19858
  required: true,
19887
- description: "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`.",
19888
- aliases: [
19889
- { name: "id", key: "id" },
19890
- { name: "plan-id", key: "planId" }
19891
- ]
19859
+ description: "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
19892
19860
  },
19893
19861
  ...selectOnlyOptions
19894
19862
  ],
@@ -19922,11 +19890,7 @@ var init_list_plan_tasks = __esm(() => {
19922
19890
  name: "planner-plan-id",
19923
19891
  key: "plannerPlanId",
19924
19892
  required: true,
19925
- description: "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`.",
19926
- aliases: [
19927
- { name: "id", key: "id" },
19928
- { name: "plan-id", key: "planId" }
19929
- ]
19893
+ description: "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
19930
19894
  }
19931
19895
  ],
19932
19896
  example: "ask-marcel-office list-plan-tasks --planner-plan-id 'xqQg5FS2LkCp935s-FIFm5gAB6'",
@@ -20014,7 +19978,6 @@ var init_list_sharepoint_site_drives = __esm(() => {
20014
19978
  name: "site-id",
20015
19979
  key: "siteId",
20016
19980
  required: true,
20017
- aliases: [{ name: "id", key: "id" }],
20018
19981
  description: "SharePoint site ID. Returned by `ask-marcel-office search-sharepoint-sites-by-name`."
20019
19982
  },
20020
19983
  ...noSkipOptions
@@ -20094,7 +20057,6 @@ var init_list_sharepoint_site_lists = __esm(() => {
20094
20057
  name: "site-id",
20095
20058
  key: "siteId",
20096
20059
  required: true,
20097
- aliases: [{ name: "id", key: "id" }],
20098
20060
  description: "SharePoint site ID. Returned by `ask-marcel-office search-sharepoint-sites-by-name`."
20099
20061
  },
20100
20062
  ...noSkipOptions
@@ -20134,7 +20096,6 @@ var init_list_specific_calendar_events = __esm(() => {
20134
20096
  name: "calendar-id",
20135
20097
  key: "calendarId",
20136
20098
  required: true,
20137
- aliases: [{ name: "id", key: "id" }],
20138
20099
  description: "Calendar ID, or the well-known short name `primary` / `default` for the signed-in user’s default calendar. Use `ask-marcel-office list-calendars` to discover non-default calendar IDs."
20139
20100
  },
20140
20101
  ...odataQueryOptions
@@ -20170,7 +20131,6 @@ var init_list_team_channels = __esm(() => {
20170
20131
  name: "team-id",
20171
20132
  key: "teamId",
20172
20133
  required: true,
20173
- aliases: [{ name: "id", key: "id" }],
20174
20134
  description: "Microsoft Teams team ID. Returned by `ask-marcel-office list-joined-teams`."
20175
20135
  },
20176
20136
  ...filterSelectOptions
@@ -20205,18 +20165,13 @@ var init_list_todo_linked_resources = __esm(() => {
20205
20165
  name: "todo-task-list-id",
20206
20166
  key: "todoTaskListId",
20207
20167
  required: true,
20208
- description: "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`.",
20209
- aliases: [
20210
- { name: "task-list-id", key: "taskListId" },
20211
- { name: "todo-list-id", key: "todoListId" }
20212
- ]
20168
+ description: "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
20213
20169
  },
20214
20170
  {
20215
20171
  name: "todo-task-id",
20216
20172
  key: "todoTaskId",
20217
20173
  required: true,
20218
- description: "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`. Accepts `--task-id` as a shorter alias (within this command's flag set the To Do context is unambiguous).",
20219
- aliases: [{ name: "task-id", key: "taskId" }]
20174
+ description: "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`."
20220
20175
  },
20221
20176
  ...odataQueryOptions
20222
20177
  ],
@@ -20289,12 +20244,7 @@ var init_list_todo_tasks = __esm(() => {
20289
20244
  name: "todo-task-list-id",
20290
20245
  key: "todoTaskListId",
20291
20246
  required: true,
20292
- description: "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`.",
20293
- aliases: [
20294
- { name: "id", key: "id" },
20295
- { name: "task-list-id", key: "taskListId" },
20296
- { name: "todo-list-id", key: "todoListId" }
20297
- ]
20247
+ description: "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
20298
20248
  },
20299
20249
  ...odataQueryOptions
20300
20250
  ],
@@ -20464,7 +20414,6 @@ var init_search_onedrive_files = __esm(() => {
20464
20414
  name: "drive-id",
20465
20415
  key: "driveId",
20466
20416
  required: true,
20467
- aliases: [{ name: "id", key: "id" }],
20468
20417
  description: "Microsoft Graph drive ID to search inside. Use `ask-marcel-office list-drives` for the personal OneDrive, or `ask-marcel-office list-sharepoint-site-drives --site-id <id>` for a SharePoint document library."
20469
20418
  },
20470
20419
  { name: "query", key: "query", required: true, description: "Free-text search query. Matches filename, content, and metadata." },
@@ -20488,7 +20437,7 @@ var noFilterShape, noFilterOptions, schema82, execute82 = async (graph, params)
20488
20437
  const parsed = schema82.safeParse(params);
20489
20438
  if (!parsed.success)
20490
20439
  return err({ type: "validation_error", message: formatZodError(parsed.error) });
20491
- const path = appendOData(`/me/onenote/pages?$filter=contains(title,'${odataStringLiteral(parsed.data.titleSubstring)}')`, parsed.data);
20440
+ const path = appendOData(`/me/onenote/pages?$filter=contains(title,'${odataStringLiteral(parsed.data.query)}')`, parsed.data);
20492
20441
  return graph.get(path);
20493
20442
  }, meta84;
20494
20443
  var init_search_onenote_pages = __esm(() => {
@@ -20497,24 +20446,23 @@ var init_search_onenote_pages = __esm(() => {
20497
20446
  init_odata_query();
20498
20447
  noFilterShape = Object.fromEntries(Object.entries(odataQuerySchema.shape).filter(([key]) => key !== "filter"));
20499
20448
  noFilterOptions = odataQueryOptions.filter((o) => o.name !== "filter");
20500
- schema82 = exports_external.object({ titleSubstring: exports_external.string().min(1) }).extend(noFilterShape);
20449
+ schema82 = exports_external.object({ query: exports_external.string().min(1) }).extend(noFilterShape);
20501
20450
  meta84 = {
20502
20451
  summary: "Find OneNote pages whose title contains a substring (case-sensitive — page content is NOT searched). Microsoft removed full-text OneNote `?search=` from v1.0 Graph; only $filter against `title` remains, which is what this command runs. Accepts the OData passthrough flags top/skip/select/orderby/expand. The filter passthrough is intentionally omitted — the path already pins a `$filter` for the title-contains predicate, and Graph rejects two `$filter` query params.",
20503
20452
  category: "notes",
20504
20453
  graphMethod: "GET",
20505
- graphPathTemplate: "/me/onenote/pages?$filter=contains(title,'{title-substring}')",
20454
+ graphPathTemplate: "/me/onenote/pages?$filter=contains(title,'{query}')",
20506
20455
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/api/onenote-list-pages",
20507
20456
  options: [
20508
20457
  {
20509
- name: "title-substring",
20510
- key: "titleSubstring",
20458
+ name: "query",
20459
+ key: "query",
20511
20460
  required: true,
20512
- description: "Substring to look for inside OneNote page titles (case-sensitive, exact substring). " + "This is title-only — full-text body search is not available on OneNote pages in v1.0 Graph. " + "Use `list-onenote-section-pages` if you already know the section.",
20513
- aliases: [{ name: "query", key: "query" }]
20461
+ description: "Substring to look for inside OneNote page TITLES (case-sensitive, exact substring — not a full-text query, despite the flag name shared with the other search commands). " + "Full-text body search is not available on OneNote pages in v1.0 Graph. " + "Use `list-onenote-section-pages` if you already know the section."
20514
20462
  },
20515
20463
  ...noFilterOptions
20516
20464
  ],
20517
- example: "ask-marcel-office search-onenote-pages --title-substring 'meeting notes' --top 25",
20465
+ example: "ask-marcel-office search-onenote-pages --query 'meeting notes' --top 25",
20518
20466
  responseShape: "collection of Microsoft Graph `onenotePage` resources under `value[]` whose title contains the substring",
20519
20467
  pagination: true
20520
20468
  };
@@ -21473,7 +21421,6 @@ var init_list_calendar_event_attachments = __esm(() => {
21473
21421
  name: "event-id",
21474
21422
  key: "eventId",
21475
21423
  required: true,
21476
- aliases: [{ name: "id", key: "id" }],
21477
21424
  description: "Outlook calendar event ID. Returned by `ask-marcel-office list-calendar-events` or `get-calendar-event`."
21478
21425
  },
21479
21426
  ...odataQueryOptions
@@ -21578,7 +21525,7 @@ var init_convert_calendar_event_attachment_to_pdf = __esm(() => {
21578
21525
  var BODY_OPEN_TAG, escapeTextAsHtml = (text) => text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll(/\r\n|\n/g, "<br>"), findBodyInsertStart = (html) => {
21579
21526
  const match = BODY_OPEN_TAG.exec(html);
21580
21527
  return match === null ? 0 : match.index + match[0].length;
21581
- }, commentCarriesQuoteBoundary = (commentHtml) => findQuoteBoundary(commentHtml) !== -1, boundaryMarkerRefusal = (flagName) => `${flagName} carries a quoted-reply boundary marker (a pasted gmail_quote container, an Outlook divRplyFwdMsg / appendonsend / border-top separator, or a bold From: + Sent: header pair). It would be kept verbatim, and a later \`update-mail-draft --comment\` edit would cut the draft at that marker and lose the real quoted history below it. Remove the pasted quote from your text, or pass --body-content-type Text to have it escaped into literal characters.`, insertCommentAboveQuote = (html, commentHtml) => {
21528
+ }, commentCarriesQuoteBoundary = (commentHtml) => findQuoteBoundary(commentHtml) !== -1, bodyCarriesQuote = (contentType, content) => contentType.toLowerCase() === "html" ? findQuoteBoundary(content) !== -1 : findPlainTextQuoteBoundary(content) !== -1, boundaryMarkerRefusal = (flagName) => `${flagName} carries a quoted-reply boundary marker (a pasted gmail_quote container, an Outlook divRplyFwdMsg / appendonsend / border-top separator, or a bold From: + Sent: header pair). It would be kept verbatim, and a later \`update-mail-draft --comment\` edit would cut the draft at that marker and lose the real quoted history below it. Remove the pasted quote from your text, or pass --body-content-type Text to have it escaped into literal characters.`, insertCommentAboveQuote = (html, commentHtml) => {
21582
21529
  const at = findBodyInsertStart(html);
21583
21530
  return { html: `${html.slice(0, at)}${commentHtml}${html.slice(at)}`, boundaryFound: findQuoteBoundary(html) !== -1 };
21584
21531
  }, replaceCommentAboveQuote = (html, commentHtml) => {
@@ -21639,7 +21586,7 @@ var schema93, isUnsentDraft = (value) => typeof value === "object" && value !==
21639
21586
  type: "api_error",
21640
21587
  status: 500,
21641
21588
  code: "draft_body_unreadable",
21642
- message: `Draft ${draftId} was created but its body could not be read back, so the comment was never written into it. The draft exists - review it in Outlook Drafts, or set its body with \`update-mail-draft --message-id ${draftId} --body-content ...\`.`
21589
+ message: `Draft ${draftId} was created but its body could not be read back, so the comment was never written into it. The draft exists - review it in Outlook Drafts, or revise it with \`update-mail-draft --message-id ${draftId}\` in comment mode (see \`ask-marcel-office docs update-mail-draft\`).`
21643
21590
  });
21644
21591
  }
21645
21592
  return ok(parsed.data.body);
@@ -21650,13 +21597,13 @@ var schema93, isUnsentDraft = (value) => typeof value === "object" && value !==
21650
21597
  type: "validation_error",
21651
21598
  message: formatZodError(parsed.error)
21652
21599
  });
21653
- const { forwardMessageId, toRecipients, ccRecipients, bodyContent, subject, bodyContentType } = parsed.data;
21600
+ const { forwardMessageId, toRecipients, ccRecipients, comment, subject, bodyContentType } = parsed.data;
21654
21601
  const asHtml = bodyContentType === "HTML";
21655
- if (asHtml && commentCarriesQuoteBoundary(bodyContent)) {
21656
- return err({ type: "validation_error", message: boundaryMarkerRefusal("--body-content") });
21602
+ if (asHtml && commentCarriesQuoteBoundary(comment)) {
21603
+ return err({ type: "validation_error", message: boundaryMarkerRefusal("--comment") });
21657
21604
  }
21658
21605
  const created = await graph.post(`/me/messages/${forwardMessageId}/createForward`, {
21659
- comment: asHtml ? "" : bodyContent,
21606
+ comment: asHtml ? "" : comment,
21660
21607
  toRecipients: parseRecipients2(toRecipients)
21661
21608
  });
21662
21609
  if (!created.ok)
@@ -21686,10 +21633,10 @@ var schema93, isUnsentDraft = (value) => typeof value === "object" && value !==
21686
21633
  if (draftBody.value.contentType.toLowerCase() !== "html") {
21687
21634
  return err({
21688
21635
  type: "validation_error",
21689
- message: `The forwarded draft's body is ${draftBody.value.contentType}, not HTML, so HTML cannot be placed above the quoted original without rewriting it. Draft ${draftId} was already created - set its text with \`update-mail-draft --message-id ${draftId} --comment "..."\`, or delete it in Outlook Drafts and retry without --body-content-type HTML.`
21636
+ message: `The forwarded draft's body is ${draftBody.value.contentType}, not HTML, so HTML cannot be placed above the quoted original without rewriting it. Draft ${draftId} was already created - revise it with \`update-mail-draft --message-id ${draftId}\` in comment mode, or delete it in Outlook Drafts and retry without --body-content-type HTML.`
21690
21637
  });
21691
21638
  }
21692
- const spliced = insertCommentAboveQuote(draftBody.value.content, bodyContent);
21639
+ const spliced = insertCommentAboveQuote(draftBody.value.content, comment);
21693
21640
  const patch = { body: { contentType: "HTML", content: spliced.html } };
21694
21641
  if (ccRecipients)
21695
21642
  patch.ccRecipients = parseRecipients2(ccRecipients);
@@ -21707,7 +21654,7 @@ var init_create_forward_draft = __esm(() => {
21707
21654
  forwardMessageId: exports_external.string().min(1),
21708
21655
  toRecipients: exports_external.string().min(1),
21709
21656
  ccRecipients: exports_external.string().optional(),
21710
- bodyContent: exports_external.string().min(1),
21657
+ comment: exports_external.string().min(1),
21711
21658
  subject: exports_external.string().optional(),
21712
21659
  bodyContentType: exports_external.enum(["Text", "HTML"]).optional()
21713
21660
  });
@@ -21723,8 +21670,7 @@ var init_create_forward_draft = __esm(() => {
21723
21670
  name: "forward-message-id",
21724
21671
  key: "forwardMessageId",
21725
21672
  required: true,
21726
- aliases: [{ name: "id", key: "id" }],
21727
- description: "The message being forwarded. Source from list-mail-folder-messages or search-mail-messages. Accepts `--id` as an alias.",
21673
+ description: "The message being forwarded. Source from list-mail-folder-messages or search-mail-messages.",
21728
21674
  argumentHint: { kind: "idOrName" }
21729
21675
  },
21730
21676
  {
@@ -21740,10 +21686,10 @@ var init_create_forward_draft = __esm(() => {
21740
21686
  description: "Comma-separated list of CC recipient email addresses."
21741
21687
  },
21742
21688
  {
21743
- name: "body-content",
21744
- key: "bodyContent",
21689
+ name: "comment",
21690
+ key: "comment",
21745
21691
  required: true,
21746
- description: "The comment text, placed above the quoted forwarded message. Plain text by default; pass --body-content-type HTML to send it as markup."
21692
+ description: "The comment text, placed above the quoted forwarded message. Named for Graph's own createForward payload field, and the same word update-mail-draft uses for the same role. Plain text by default; pass --body-content-type HTML to send it as markup."
21747
21693
  },
21748
21694
  {
21749
21695
  name: "subject",
@@ -21755,12 +21701,12 @@ var init_create_forward_draft = __esm(() => {
21755
21701
  name: "body-content-type",
21756
21702
  key: "bodyContentType",
21757
21703
  required: false,
21758
- description: "Format of --body-content: Text (default) or HTML. Text is handed to Graph as the forward comment, which HTML-escapes it, so markup shows as literal characters. HTML instead creates the draft with an empty comment and splices your markup in at the TOP of the body — above Graph's separator (the `<hr>` line) and the forwarded original, so your comment leads the body content — leaving the original and its styles byte-identical. Rejected when your markup itself contains a quote boundary marker (a pasted reply chain), and when the original is a plain-text message.",
21704
+ description: "Format of --comment: Text (default) or HTML. Text is handed to Graph as the forward comment, which HTML-escapes it, so markup shows as literal characters. HTML instead creates the draft with an empty comment and splices your markup in at the TOP of the body — above Graph's separator (the `<hr>` line) and the forwarded original, so your comment leads the body content — leaving the original and its styles byte-identical. Rejected when your markup itself contains a quote boundary marker (a pasted reply chain), and when the original is a plain-text message.",
21759
21705
  argumentHint: { kind: "magicValue", values: ["Text", "HTML"] }
21760
21706
  }
21761
21707
  ],
21762
- example: 'ask-marcel-office create-forward-draft --forward-message-id "AAMkAD..." --to-recipients "bob@example.com" --body-content "Bob owns this now, forwarding for your action."',
21763
- bodyTemplate: "Text: POST { comment: '{body-content}', toRecipients: '{to-recipients}' } then optional PATCH { ccRecipients?: '{cc-recipients}', subject?: '{subject}' }. HTML ({body-content-type}): POST { comment: '', toRecipients: '{to-recipients}' } then ONE PATCH { body: { contentType: 'HTML', content: <'{body-content}' spliced at the top of the body, above Graph's <hr> separator and the quote> }, ccRecipients?: '{cc-recipients}', subject?: '{subject}' }",
21708
+ example: 'ask-marcel-office create-forward-draft --forward-message-id "AAMkAD..." --to-recipients "bob@example.com" --comment "Bob owns this now, forwarding for your action."',
21709
+ bodyTemplate: "Text: POST { comment: '{comment}', toRecipients: '{to-recipients}' } then optional PATCH { ccRecipients?: '{cc-recipients}', subject?: '{subject}' }. HTML ({body-content-type}): POST { comment: '', toRecipients: '{to-recipients}' } then ONE PATCH { body: { contentType: 'HTML', content: <'{comment}' spliced at the top of the body, above Graph's <hr> separator and the quote> }, ccRecipients?: '{cc-recipients}', subject?: '{subject}' }",
21764
21710
  mutates: true,
21765
21711
  scopesRequired: ["Mail.ReadWrite"],
21766
21712
  responseShape: "A confirmation of the write, NOT the whole message: `{ id, subject, toRecipients, ccRecipients, bccRecipients, importance, bodyPreview, isDraft, webLink, conversationId }` (only the fields Graph returned; `{ ok: true }` when Graph answers 204). The `body` is deliberately omitted — you just wrote it, and echoing a long thread's quoted history back cost ~174 KB of context per call. Read the full body with `get-mail-message --id <the returned id>` when you actually need it; `bodyPreview` is Graph's ~255-char summary, enough to confirm WHICH draft answered. The `id` is the draft — refine it with `update-mail-draft`, or open Outlook Drafts to review and send. Dedup caveat: a `conversationId` `$filter` on the Drafts folder is not a reliable 'does a draft already exist on this thread' check. Reply and forward drafts do not always inherit the inbound message's `conversationId` (one thread can split across several), and Graph `$filter` on Drafts is not read-your-writes consistent, so a just-created draft can be missed. To find existing drafts, use the `find-mail-drafts` command, which scans recent drafts and matches client-side on subject and recipients; to revise a draft this session created, reuse the returned `id`."
@@ -21898,7 +21844,7 @@ var schema95, isUnsentDraft2 = (value) => typeof value === "object" && value !==
21898
21844
  type: "api_error",
21899
21845
  status: 500,
21900
21846
  code: "draft_body_unreadable",
21901
- message: `Draft ${draftId} was created but its body could not be read back, so the reply text was never written into it. The draft exists - review it in Outlook Drafts, or set its body with \`update-mail-draft --message-id ${draftId} --body-content ...\`.`
21847
+ message: `Draft ${draftId} was created but its body could not be read back, so the reply text was never written into it. The draft exists - review it in Outlook Drafts, or revise it with \`update-mail-draft --message-id ${draftId}\` in comment mode (see \`ask-marcel-office docs update-mail-draft\`).`
21902
21848
  });
21903
21849
  }
21904
21850
  return ok(parsed.data.body);
@@ -21906,13 +21852,13 @@ var schema95, isUnsentDraft2 = (value) => typeof value === "object" && value !==
21906
21852
  const parsed = schema95.safeParse(params);
21907
21853
  if (!parsed.success)
21908
21854
  return err({ type: "validation_error", message: formatZodError(parsed.error) });
21909
- const { replyToMessageId, bodyContent, subject, replyAll, bodyContentType } = parsed.data;
21855
+ const { replyToMessageId, comment, subject, replyAll, bodyContentType } = parsed.data;
21910
21856
  const action = replyAll === "false" ? "createReply" : "createReplyAll";
21911
21857
  const asHtml = bodyContentType === "HTML";
21912
- if (asHtml && commentCarriesQuoteBoundary(bodyContent)) {
21913
- return err({ type: "validation_error", message: boundaryMarkerRefusal("--body-content") });
21858
+ if (asHtml && commentCarriesQuoteBoundary(comment)) {
21859
+ return err({ type: "validation_error", message: boundaryMarkerRefusal("--comment") });
21914
21860
  }
21915
- const created = await graph.post(`/me/messages/${replyToMessageId}/${action}`, { comment: asHtml ? "" : bodyContent });
21861
+ const created = await graph.post(`/me/messages/${replyToMessageId}/${action}`, { comment: asHtml ? "" : comment });
21916
21862
  if (!created.ok)
21917
21863
  return created;
21918
21864
  if (!isUnsentDraft2(created.value)) {
@@ -21938,10 +21884,10 @@ var schema95, isUnsentDraft2 = (value) => typeof value === "object" && value !==
21938
21884
  if (draftBody.value.contentType.toLowerCase() !== "html") {
21939
21885
  return err({
21940
21886
  type: "validation_error",
21941
- message: `The thread's draft body is ${draftBody.value.contentType}, not HTML, so HTML cannot be placed above its quoted history without rewriting the quote. Draft ${draftId} was already created - reply to it with \`update-mail-draft --message-id ${draftId} --comment "..."\`, or delete it in Outlook Drafts and retry without --body-content-type HTML.`
21887
+ message: `The thread's draft body is ${draftBody.value.contentType}, not HTML, so HTML cannot be placed above its quoted history without rewriting the quote. Draft ${draftId} was already created - revise it with \`update-mail-draft --message-id ${draftId}\` in comment mode, or delete it in Outlook Drafts and retry without --body-content-type HTML.`
21942
21888
  });
21943
21889
  }
21944
- const spliced = insertCommentAboveQuote(draftBody.value.content, bodyContent);
21890
+ const spliced = insertCommentAboveQuote(draftBody.value.content, comment);
21945
21891
  const patch = { body: { contentType: "HTML", content: spliced.html } };
21946
21892
  if (subject)
21947
21893
  patch.subject = subject;
@@ -21954,7 +21900,7 @@ var init_create_reply_draft = __esm(() => {
21954
21900
  init_format_zod_error();
21955
21901
  schema95 = exports_external.object({
21956
21902
  replyToMessageId: exports_external.string().min(1),
21957
- bodyContent: exports_external.string().min(1),
21903
+ comment: exports_external.string().min(1),
21958
21904
  subject: exports_external.string().optional(),
21959
21905
  replyAll: exports_external.enum(["true", "false"]).optional(),
21960
21906
  bodyContentType: exports_external.enum(["Text", "HTML"]).optional()
@@ -21971,21 +21917,20 @@ var init_create_reply_draft = __esm(() => {
21971
21917
  name: "reply-to-message-id",
21972
21918
  key: "replyToMessageId",
21973
21919
  required: true,
21974
- aliases: [{ name: "id", key: "id" }],
21975
- description: "The message being replied to. Source from list-mail-folder-messages or search-mail-messages. Accepts `--id` as an alias.",
21920
+ description: "The message being replied to. Source from list-mail-folder-messages or search-mail-messages.",
21976
21921
  argumentHint: { kind: "idOrName" }
21977
21922
  },
21978
21923
  {
21979
- name: "body-content",
21980
- key: "bodyContent",
21924
+ name: "comment",
21925
+ key: "comment",
21981
21926
  required: true,
21982
- description: "The reply text, placed above the quoted history. Plain text by default; pass --body-content-type HTML to send it as markup."
21927
+ description: "The reply text, placed above the quoted history. Named for Graph's own createReply payload field, and the same word update-mail-draft uses for the same role. Plain text by default; pass --body-content-type HTML to send it as markup."
21983
21928
  },
21984
21929
  {
21985
21930
  name: "body-content-type",
21986
21931
  key: "bodyContentType",
21987
21932
  required: false,
21988
- description: "Format of --body-content: Text (default) or HTML. Text is handed to Graph as the reply comment, which HTML-escapes it, so markup shows as literal characters. HTML instead creates the draft with an empty comment and splices your markup in at the TOP of the body — above Graph's reply separator (the `<hr>` line) and the quoted thread, so your reply leads the body content — leaving the quoted thread and its styles byte-identical. Rejected when your markup itself contains a quote boundary marker (a pasted reply chain), and when the thread is a plain-text one.",
21933
+ description: "Format of --comment: Text (default) or HTML. Text is handed to Graph as the reply comment, which HTML-escapes it, so markup shows as literal characters. HTML instead creates the draft with an empty comment and splices your markup in at the TOP of the body — above Graph's reply separator (the `<hr>` line) and the quoted thread, so your reply leads the body content — leaving the quoted thread and its styles byte-identical. Rejected when your markup itself contains a quote boundary marker (a pasted reply chain), and when the thread is a plain-text one.",
21989
21934
  argumentHint: { kind: "magicValue", values: ["Text", "HTML"] }
21990
21935
  },
21991
21936
  {
@@ -22002,8 +21947,8 @@ var init_create_reply_draft = __esm(() => {
22002
21947
  argumentHint: { kind: "magicValue", values: ["true", "false"] }
22003
21948
  }
22004
21949
  ],
22005
- example: 'ask-marcel-office create-reply-draft --reply-to-message-id "AAMkAD..." --body-content "Confirmed for Contoso, aligned with the group choice."',
22006
- bodyTemplate: "Text: POST { comment: '{body-content}' } then optional PATCH { subject?: '{subject}' }. HTML ({body-content-type}): POST { comment: '' } then ONE PATCH { body: { contentType: 'HTML', content: <'{body-content}' spliced at the top of the body, above Graph's <hr> separator and the quote> }, subject?: '{subject}' }",
21950
+ example: 'ask-marcel-office create-reply-draft --reply-to-message-id "AAMkAD..." --comment "Confirmed for Contoso, aligned with the group choice."',
21951
+ bodyTemplate: "Text: POST { comment: '{comment}' } then optional PATCH { subject?: '{subject}' }. HTML ({body-content-type}): POST { comment: '' } then ONE PATCH { body: { contentType: 'HTML', content: <'{comment}' spliced at the top of the body, above Graph's <hr> separator and the quote> }, subject?: '{subject}' }",
22007
21952
  mutates: true,
22008
21953
  scopesRequired: ["Mail.ReadWrite"],
22009
21954
  responseShape: "A confirmation of the write, NOT the whole message: `{ id, subject, toRecipients, ccRecipients, bccRecipients, importance, bodyPreview, isDraft, webLink, conversationId }` (only the fields Graph returned; `{ ok: true }` when Graph answers 204). The `body` is deliberately omitted — you just wrote it, and echoing a long thread's quoted history back cost ~174 KB of context per call. Read the full body with `get-mail-message --id <the returned id>` when you actually need it; `bodyPreview` is Graph's ~255-char summary, enough to confirm WHICH draft answered. The `id` is the draft — refine it with `update-mail-draft`, or open Outlook Drafts to review and send. Dedup caveat: a `conversationId` `$filter` on the Drafts folder is not a reliable 'does a draft already exist on this thread' check. Reply and forward drafts do not always inherit the inbound message's `conversationId` (one thread can split across several), and Graph `$filter` on Drafts is not read-your-writes consistent, so a just-created draft can be missed. To find existing drafts, use the `find-mail-drafts` command, which scans recent drafts and matches client-side on subject and recipients; to revise a draft this session created, reuse the returned `id`."
@@ -22020,6 +21965,9 @@ __export(exports_update_mail_draft, {
22020
21965
  var schema96, draftSchema2, noQuoteRefusal = (messageId) => ({
22021
21966
  type: "validation_error",
22022
21967
  message: `Draft ${messageId} has no quoted reply history to preserve, so there is nothing for --comment to sit above. Use --body-content to replace the whole body instead.`
21968
+ }), quotedHistoryRefusal = (messageId) => ({
21969
+ type: "validation_error",
21970
+ message: `Draft ${messageId} carries quoted reply history, and --body-content replaces the entire body, quote included. Revise only your own text with --comment, which keeps the quote byte-identical, or pass --replace-quoted-history true to drop the quote deliberately.`
22023
21971
  }), reviseBodyAboveQuote = (draft, messageId, comment, asHtml) => {
22024
21972
  if (draft.contentType.toLowerCase() !== "html") {
22025
21973
  if (asHtml) {
@@ -22052,11 +22000,18 @@ var schema96, draftSchema2, noQuoteRefusal = (messageId) => ({
22052
22000
  return err({ type: "validation_error", message: `Message ${messageId} is not a draft, so its body cannot be revised. Only unsent drafts can be updated.` });
22053
22001
  }
22054
22002
  return ok(parsed.data);
22003
+ }, guardQuotedHistory = async (graph, messageId) => {
22004
+ const draft = await readDraft(graph, messageId);
22005
+ if (!draft.ok)
22006
+ return draft;
22007
+ if (!bodyCarriesQuote(draft.value.body.contentType, draft.value.body.content))
22008
+ return ok(undefined);
22009
+ return err(quotedHistoryRefusal(messageId));
22055
22010
  }, execute96 = async (graph, params) => {
22056
22011
  const parsed = schema96.safeParse(params);
22057
22012
  if (!parsed.success)
22058
22013
  return err({ type: "validation_error", message: formatZodError(parsed.error) });
22059
- const { messageId, subject, bodyContent, comment, bodyContentType, toRecipients, ccRecipients, bccRecipients, importance } = parsed.data;
22014
+ const { messageId, subject, bodyContent, comment, replaceQuotedHistory, bodyContentType, toRecipients, ccRecipients, bccRecipients, importance } = parsed.data;
22060
22015
  if ([subject, bodyContent, comment, toRecipients, ccRecipients, bccRecipients, importance].every((v) => v === undefined)) {
22061
22016
  return err({
22062
22017
  type: "validation_error",
@@ -22072,6 +22027,11 @@ var schema96, draftSchema2, noQuoteRefusal = (messageId) => ({
22072
22027
  if (comment !== undefined && bodyContentType === "HTML" && commentCarriesQuoteBoundary(comment)) {
22073
22028
  return err({ type: "validation_error", message: boundaryMarkerRefusal("--comment") });
22074
22029
  }
22030
+ if (bodyContent !== undefined && replaceQuotedHistory !== "true") {
22031
+ const guarded = await guardQuotedHistory(graph, messageId);
22032
+ if (!guarded.ok)
22033
+ return guarded;
22034
+ }
22075
22035
  const body = {};
22076
22036
  if (subject !== undefined)
22077
22037
  body.subject = subject;
@@ -22107,6 +22067,7 @@ var init_update_mail_draft = __esm(() => {
22107
22067
  subject: exports_external.string().optional(),
22108
22068
  bodyContent: exports_external.string().optional(),
22109
22069
  comment: exports_external.string().min(1).optional(),
22070
+ replaceQuotedHistory: exports_external.enum(["true", "false"]).optional(),
22110
22071
  bodyContentType: exports_external.enum(["Text", "HTML"]).optional(),
22111
22072
  toRecipients: exports_external.string().optional(),
22112
22073
  ccRecipients: exports_external.string().optional(),
@@ -22115,18 +22076,17 @@ var init_update_mail_draft = __esm(() => {
22115
22076
  });
22116
22077
  draftSchema2 = exports_external.object({ isDraft: exports_external.boolean(), body: exports_external.object({ contentType: exports_external.string(), content: exports_external.string() }) });
22117
22078
  meta98 = {
22118
- summary: "Update an existing mail draft. PATCH /me/messages/{id} — modifies a draft created by create-mail-draft (or any existing draft in the Drafts folder). Only the fields you pass are updated; omitted fields are left unchanged. At least one field must be provided. On a THREADED draft (one made by create-reply-draft / create-forward-draft), revise your text with --comment, which rewrites only what sits above the quoted history and leaves the quote byte-identical; --body-content would replace the whole body and drop the thread. Passing an EMPTY string to a recipient flag clears that list, which is how you drop recipients a reply-all or forward inherited; omitting the flag leaves the list alone. Returns a slim confirmation (id, subject, recipients, importance, bodyPreview, …) - NOT the full body, which you just wrote; read it back with get-mail-message if you need the whole draft before sending.",
22079
+ summary: "Update an existing mail draft. PATCH /me/messages/{id} — modifies a draft created by create-mail-draft (or any existing draft in the Drafts folder). Only the fields you pass are updated; omitted fields are left unchanged. At least one field must be provided. On a THREADED draft (one made by create-reply-draft / create-forward-draft), revise your text with --comment, which rewrites only what sits above the quoted history and leaves the quote byte-identical; --body-content replaces the whole body and would drop the thread, so it is REFUSED on a draft that still carries a quote unless you pass --replace-quoted-history true. Passing an EMPTY string to a recipient flag clears that list, which is how you drop recipients a reply-all or forward inherited; omitting the flag leaves the list alone. Returns a slim confirmation (id, subject, recipients, importance, bodyPreview, …) - NOT the full body, which you just wrote; read it back with get-mail-message if you need the whole draft before sending.",
22119
22080
  category: "mail",
22120
22081
  graphMethod: "PATCH",
22121
- graphPathTemplate: "/me/messages/{message-id} (+ a GET of body,isDraft first when {comment} is used)",
22082
+ graphPathTemplate: "/me/messages/{message-id} (+ a GET of body,isDraft first when {comment} is used, or when {body-content} is used without {replace-quoted-history})",
22122
22083
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/api/message-update",
22123
22084
  options: [
22124
22085
  {
22125
22086
  name: "message-id",
22126
22087
  key: "messageId",
22127
22088
  required: true,
22128
- aliases: [{ name: "id", key: "id" }],
22129
- description: "Draft message ID to update. Source from create-mail-draft response or list-mail-folder-messages --mail-folder-id drafts. Accepts `--id` as an alias.",
22089
+ description: "Draft message ID to update. Source from create-mail-draft response or list-mail-folder-messages --mail-folder-id drafts.",
22130
22090
  argumentHint: { kind: "idOrName" }
22131
22091
  },
22132
22092
  {
@@ -22139,7 +22099,7 @@ var init_update_mail_draft = __esm(() => {
22139
22099
  name: "body-content",
22140
22100
  key: "bodyContent",
22141
22101
  required: false,
22142
- description: "New email body content. Replaces the ENTIRE body, quoted history included. On a threaded reply or forward draft this is almost never what you want - use --comment to revise only your own text and keep the quote. Pass --body-content-type HTML for rich text. Mutually exclusive with --comment."
22102
+ description: "New email body content. Replaces the ENTIRE body, quoted history included. On a threaded reply or forward draft that is almost never what you want, so the command reads the draft first and REFUSES when it still carries a quote - use --comment to revise only your own text and keep the quote, or pass --replace-quoted-history true to drop it deliberately. Note the sibling commands: create-reply-draft / create-forward-draft name their above-the-quote text --comment; --body-content exists only here. Pass --body-content-type HTML for rich text. Mutually exclusive with --comment."
22143
22103
  },
22144
22104
  {
22145
22105
  name: "comment",
@@ -22147,6 +22107,13 @@ var init_update_mail_draft = __esm(() => {
22147
22107
  required: false,
22148
22108
  description: "Rewrite ONLY the reply text above the quoted history on a threaded draft, keeping the quote and its styles byte-identical. This is the flag for revising a draft made by create-reply-draft or create-forward-draft; repeated edits replace your text rather than stacking. Refused when the draft has no quoted history (use --body-content), when it is not a draft, and when HTML markup you pass carries a quote boundary marker of its own. Mutually exclusive with --body-content."
22149
22109
  },
22110
+ {
22111
+ name: "replace-quoted-history",
22112
+ key: "replaceQuotedHistory",
22113
+ required: false,
22114
+ description: "Allow --body-content to drop the quoted history on a threaded draft. Without it, --body-content is REFUSED when the draft still carries a quote, because replacing the whole body there silently loses the thread; the refusal points at --comment, which revises only your own text. Pass `true` for the deliberate case: strip the quote but keep the draft threaded on its conversation. Ignored in comment mode, which never touches the quote.",
22115
+ argumentHint: { kind: "magicValue", values: ["true", "false"] }
22116
+ },
22150
22117
  {
22151
22118
  name: "body-content-type",
22152
22119
  key: "bodyContentType",
@@ -22181,7 +22148,7 @@ var init_update_mail_draft = __esm(() => {
22181
22148
  }
22182
22149
  ],
22183
22150
  example: 'ask-marcel-office update-mail-draft --message-id "AAMkAD..." --subject "Updated: Q3 Report" --to-recipients "alice@example.com,charlie@example.com"',
22184
- bodyTemplate: "{ subject?: '{subject}', body?: { contentType: '{body-content-type}', content: '{body-content}' }, toRecipients?: '{to-recipients}', ccRecipients?: '{cc-recipients}', bccRecipients?: '{bcc-recipients}', importance?: '{importance}' } — only provided fields are sent. With '{comment}': body.content is the draft's own body with the text above the quote replaced, and body.contentType is the draft's own, unchanged",
22151
+ bodyTemplate: "{ subject?: '{subject}', body?: { contentType: '{body-content-type}', content: '{body-content}' }, toRecipients?: '{to-recipients}', ccRecipients?: '{cc-recipients}', bccRecipients?: '{bcc-recipients}', importance?: '{importance}' } — only provided fields are sent. With '{comment}': body.content is the draft's own body with the text above the quote replaced, and body.contentType is the draft's own, unchanged. A '{body-content}' aimed at a draft that still carries a quote costs one GET of body,isDraft and is refused unless '{replace-quoted-history}' is true",
22185
22152
  mutates: true,
22186
22153
  scopesRequired: ["Mail.ReadWrite"],
22187
22154
  responseShape: "A confirmation of the write, NOT the whole message: `{ id, subject, toRecipients, ccRecipients, bccRecipients, importance, bodyPreview, isDraft, webLink, conversationId }` (only the fields Graph returned; `{ ok: true }` when Graph answers 204). The `body` is deliberately omitted — you just wrote it, and echoing a long thread's quoted history back cost ~174 KB of context per call. Read the full body with `get-mail-message --id <the returned id>` when you actually need it; `bodyPreview` is Graph's ~255-char summary, enough to confirm WHICH draft answered. The `id` is the draft — refine it with `update-mail-draft`, or open Outlook Drafts to review and send. Dedup caveat: a `conversationId` `$filter` on the Drafts folder is not a reliable 'does a draft already exist on this thread' check. Reply and forward drafts do not always inherit the inbound message's `conversationId` (one thread can split across several), and Graph `$filter` on Drafts is not read-your-writes consistent, so a just-created draft can be missed. To find existing drafts, use the `find-mail-drafts` command, which scans recent drafts and matches client-side on subject and recipients; to revise a draft this session created, reuse the returned `id`."
@@ -22227,7 +22194,6 @@ var init_convert_drive_item_zip_to_markdown = __esm(() => {
22227
22194
  meta99 = {
22228
22195
  summary: "Unzip a `.zip` from a OneDrive / SharePoint item and convert every contained file in one call — so \"read the handover archive\" doesn't need a separate unzip + per-file conversion. Office files (docx/xlsx/pptx/odt/ods/odp and their macro-enabled / template variants) are converted to markdown via the local pipelines; plain-text entries (txt/md/csv/json/yaml/…) are decoded inline; legacy OLE .xls (sheetjs) and .doc (word-extractor, text only) are extracted; an Outlook .msg entry is rendered to markdown (headers + body, with its own attachments converted recursively); PDFs have their text layer extracted (text/plain); images, binaries, nested archives, legacy .ppt, and scanned/image-only PDFs (no text layer) are listed with a note (not unpacked) so one unsupported entry never fails the whole archive. Pass `--include-metadata true` to append each Office file's side-channel metadata block. Capped at 100 entries (the archive is buffered in memory); beyond that the response is flagged `truncated`.",
22229
22196
  category: "drive",
22230
- commandAliases: ["convert-drive-item-zip"],
22231
22197
  graphMethod: "GET",
22232
22198
  graphPathTemplate: "/drives/{drive-id}/items/{item-id}/content",
22233
22199
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/api/driveitem-get-content",
@@ -22312,7 +22278,6 @@ var init_convert_local_file_to_markdown = __esm(() => {
22312
22278
  meta100 = {
22313
22279
  summary: "Convert a file ON DISK to markdown — the only command that never calls Microsoft Graph (works offline, no login). Runs the same local pipelines as `download-drive-item-as-markdown`: docx (mammoth → turndown), xlsx (sheetjs tables, `--max-cells` OOM cap), pptx (per-slide text), odt/ods/odp, csv, pdf (text layer via unpdf), legacy OLE .xls / .doc, Outlook .msg (headers + body with the quoted reply chain stripped — `--keep-quoted true` restores it — and inline `cid:` images shown as placeholders, attachments converted recursively), plain-text passthrough — and a `.zip` is unpacked with every contained file converted in one call (legacy GBK / CP437 entry names decoded, not mojibaked). What it canNOT do locally: convert TO pdf, and Loop/Fluid/Whiteboard sources — both need a Graph server round-trip (upload to OneDrive and use the drive-item siblings). Pass `--include-metadata true` for the Office side-channel metadata blocks; `--inline-images true` to embed docx images as base64 data URIs.",
22314
22280
  category: "meta",
22315
- commandAliases: ["convert-local-file"],
22316
22281
  graphMethod: "GET",
22317
22282
  graphPathTemplate: "(local) reads {path} from the local filesystem; not a Graph endpoint",
22318
22283
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/",
@@ -22455,7 +22420,6 @@ var init_convert_mail_attachment_zip_to_markdown = __esm(() => {
22455
22420
  meta102 = {
22456
22421
  summary: "Unzip a `.zip` Outlook mail attachment and convert every contained file in one call — the mail-side mirror of `convert-drive-item-zip-to-markdown`, so reading a zipped vendor deck doesn't need `get-mail-attachment` + manual `unzip` + per-file conversion. Pulls the fileAttachment bytes, unzips them (legacy GBK / CP437 entry names — Chinese vendor archives written by WinRAR / Windows Explorer — are decoded correctly, not mojibaked), and runs each file through the local pipelines: Office files (docx/xlsx/pptx/odt/ods/odp and macro-enabled / template variants) → markdown; plain-text entries decoded inline; legacy OLE .xls (sheetjs) and .doc (word-extractor, text only) extracted; an inner Outlook .msg rendered; PDFs have their text layer extracted; images, binaries, nested archives, legacy .ppt, and scanned/image-only PDFs are listed with a note (not unpacked) so one unsupported entry never fails the whole archive. Pass `--include-metadata true` to append each Office file's side-channel metadata block. Capped at 100 entries; beyond that the response is flagged `truncated`. itemAttachment / referenceAttachment are rejected (no inline zip payload).",
22457
22422
  category: "mail",
22458
- commandAliases: ["convert-mail-attachment-zip"],
22459
22423
  graphMethod: "GET",
22460
22424
  graphPathTemplate: "/me/messages/{message-id}/attachments/{attachment-id}",
22461
22425
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/api/attachment-get",
@@ -22581,8 +22545,7 @@ var init_extract_sharepoint_links_in_mail = __esm(() => {
22581
22545
  name: "message-id",
22582
22546
  key: "messageId",
22583
22547
  required: true,
22584
- aliases: [{ name: "id", key: "id" }],
22585
- description: "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
22548
+ description: "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`."
22586
22549
  }
22587
22550
  ],
22588
22551
  example: "ask-marcel-office extract-sharepoint-links-in-mail --message-id 'AAMkADk0...'",
@@ -22644,7 +22607,6 @@ var init_get_chat = __esm(() => {
22644
22607
  name: "chat-id",
22645
22608
  key: "chatId",
22646
22609
  required: true,
22647
- aliases: [{ name: "id", key: "id" }],
22648
22610
  description: "Microsoft Teams chat ID, e.g. `19:abc...@thread.v2`. Returned by `list-chats`."
22649
22611
  },
22650
22612
  ...selectExpandOptions
@@ -22738,7 +22700,6 @@ var init_list_teams_chat_messages = __esm(() => {
22738
22700
  name: "chat-id",
22739
22701
  key: "chatId",
22740
22702
  required: true,
22741
- aliases: [{ name: "id", key: "id" }],
22742
22703
  description: "Teams chat ID — typically `19:<thread>@unq.gbl.spaces` (1:1) or `19:<thread>@thread.v2` (group). Source via `list-chats` or `list-teams-chats-with-messages`."
22743
22704
  }
22744
22705
  ],
@@ -22837,7 +22798,6 @@ var init_list_teams_chat_history = __esm(() => {
22837
22798
  name: "chat-id",
22838
22799
  key: "chatId",
22839
22800
  required: true,
22840
- aliases: [{ name: "id", key: "id" }],
22841
22801
  description: "Teams chat ID — typically `19:<thread>@unq.gbl.spaces` (1:1) or `19:<thread>@thread.v2` (group). Source via `list-chats` or `list-teams-chats-with-messages`."
22842
22802
  },
22843
22803
  {
@@ -23558,7 +23518,6 @@ var init_list_user_direct_reports = __esm(() => {
23558
23518
  name: "user-id",
23559
23519
  key: "userId",
23560
23520
  required: true,
23561
- aliases: [{ name: "id", key: "id" }],
23562
23521
  description: "Azure AD user ID or userPrincipalName (UPN) — typically the user's email address. Discover via `list-relevant-people` (relevance-ranked colleagues) or `microsoft-search-query --query <name>` (federated person search across the tenant directory)."
23563
23522
  },
23564
23523
  ...odataQueryOptions
@@ -23873,7 +23832,6 @@ var init_list_team_installed_apps = __esm(() => {
23873
23832
  name: "team-id",
23874
23833
  key: "teamId",
23875
23834
  required: true,
23876
- aliases: [{ name: "id", key: "id" }],
23877
23835
  description: "Microsoft Teams team ID."
23878
23836
  }
23879
23837
  ],
@@ -23935,7 +23893,6 @@ var init_list_calendar_group_calendars = __esm(() => {
23935
23893
  name: "calendar-group-id",
23936
23894
  key: "calendarGroupId",
23937
23895
  required: true,
23938
- aliases: [{ name: "id", key: "id" }],
23939
23896
  description: "Calendar group ID. Returned by `list-calendar-groups`."
23940
23897
  },
23941
23898
  ...odataQueryOptions
@@ -23997,7 +23954,6 @@ var init_list_site_columns = __esm(() => {
23997
23954
  name: "site-id",
23998
23955
  key: "siteId",
23999
23956
  required: true,
24000
- aliases: [{ name: "id", key: "id" }],
24001
23957
  description: "SharePoint site ID. Returned by `search-sharepoint-sites-by-name`."
24002
23958
  },
24003
23959
  ...selectExpandOptions
@@ -24032,7 +23988,6 @@ var init_list_site_content_types = __esm(() => {
24032
23988
  name: "site-id",
24033
23989
  key: "siteId",
24034
23990
  required: true,
24035
- aliases: [{ name: "id", key: "id" }],
24036
23991
  description: "SharePoint site ID."
24037
23992
  },
24038
23993
  ...noSkipOptions
@@ -24069,7 +24024,6 @@ var init_list_sharepoint_site_pages = __esm(() => {
24069
24024
  name: "site-id",
24070
24025
  key: "siteId",
24071
24026
  required: true,
24072
- aliases: [{ name: "id", key: "id" }],
24073
24027
  description: "SharePoint site ID."
24074
24028
  },
24075
24029
  ...noSkipOptions
@@ -24372,15 +24326,15 @@ var init_get_drive_root_delta = __esm(() => {
24372
24326
  init_zod();
24373
24327
  init_build_command();
24374
24328
  init_odata_query();
24375
- baseSchema67 = exports_external.object({}).strict();
24376
- ({ execute: execute138, schema: schema138 } = buildNoSkipListCommand(() => "/me/drive/root/delta()", baseSchema67));
24329
+ baseSchema67 = exports_external.object({});
24330
+ ({ execute: execute138, schema: schema138 } = buildPickODataListCommand(() => "/me/drive/root/delta()", baseSchema67, ["top", "select", "expand"]));
24377
24331
  meta140 = {
24378
24332
  summary: "Track incremental changes (added / modified / deleted items) anywhere under the signed-in user's OneDrive root. **Takes zero required arguments** — acts implicitly on the signed-in user's primary OneDrive; use `get-drive-delta` to target a specific drive by ID. The first call returns a snapshot plus `@odata.deltaLink`; subsequent calls with that link return only what has changed since. Cross-folder companion to `get-drive-delta` (which scopes to one specific folder).",
24379
24333
  category: "drive",
24380
24334
  graphMethod: "GET",
24381
24335
  graphPathTemplate: "/me/drive/root/delta()",
24382
24336
  graphDocsUrl: "https://learn.microsoft.com/en-us/graph/api/driveitem-delta",
24383
- options: [...noSkipOptions],
24337
+ options: [...pickODataOptions(["top", "select", "expand"])],
24384
24338
  example: "ask-marcel-office get-drive-root-delta",
24385
24339
  responseShape: "collection of Microsoft Graph `driveItem` resources under `data.value[]`. Cursor tokens are hoisted to envelope level: top-level `nextLink` while paging, then top-level `deltaLink` on the final page.",
24386
24340
  pagination: true,
@@ -24520,7 +24474,6 @@ var init_get_site_analytics = __esm(() => {
24520
24474
  name: "site-id",
24521
24475
  key: "siteId",
24522
24476
  required: true,
24523
- aliases: [{ name: "id", key: "id" }],
24524
24477
  description: "SharePoint site ID."
24525
24478
  }
24526
24479
  ],
@@ -24566,8 +24519,7 @@ var init_list_sharepoint_list_item_versions = __esm(() => {
24566
24519
  name: "list-item-id",
24567
24520
  key: "listItemId",
24568
24521
  required: true,
24569
- description: "List item ID inside the list. Returned by `list-sharepoint-site-list-items`.",
24570
- aliases: [{ name: "item-id", key: "itemId" }]
24522
+ description: "List item ID inside the list. Returned by `list-sharepoint-site-list-items`."
24571
24523
  },
24572
24524
  ...noSkipOptions
24573
24525
  ],
@@ -24608,11 +24560,7 @@ var init_get_mail_rule = __esm(() => {
24608
24560
  name: "message-rule-id",
24609
24561
  key: "messageRuleId",
24610
24562
  required: true,
24611
- description: "Message rule ID. Returned by `list-mail-rules`.",
24612
- aliases: [
24613
- { name: "id", key: "id" },
24614
- { name: "rule-id", key: "ruleId" }
24615
- ]
24563
+ description: "Message rule ID. Returned by `list-mail-rules`."
24616
24564
  }
24617
24565
  ],
24618
24566
  example: "ask-marcel-office get-mail-rule --message-rule-id 'AQAAANC...'",
@@ -24794,7 +24742,6 @@ var init_get_team_primary_channel = __esm(() => {
24794
24742
  name: "team-id",
24795
24743
  key: "teamId",
24796
24744
  required: true,
24797
- aliases: [{ name: "id", key: "id" }],
24798
24745
  description: "Microsoft Teams team ID. Returned by `list-joined-teams`."
24799
24746
  },
24800
24747
  ...selectExpandOptions
@@ -24828,12 +24775,7 @@ var init_list_todo_tasks_delta = __esm(() => {
24828
24775
  name: "todo-task-list-id",
24829
24776
  key: "todoTaskListId",
24830
24777
  required: true,
24831
- description: "Microsoft To Do task list ID. Returned by `list-todo-task-lists`.",
24832
- aliases: [
24833
- { name: "id", key: "id" },
24834
- { name: "task-list-id", key: "taskListId" },
24835
- { name: "todo-list-id", key: "todoListId" }
24836
- ]
24778
+ description: "Microsoft To Do task list ID. Returned by `list-todo-task-lists`."
24837
24779
  }
24838
24780
  ],
24839
24781
  example: "ask-marcel-office list-todo-tasks-delta --todo-task-list-id 'AAMkAD...'",
@@ -24968,7 +24910,6 @@ var init_get_user = __esm(() => {
24968
24910
  name: "user-id",
24969
24911
  key: "userId",
24970
24912
  required: true,
24971
- aliases: [{ name: "id", key: "id" }],
24972
24913
  description: "Azure AD user ID, UPN, or email (returns the full profile via the elevated token), OR a display name (returns relevant-people candidates on the basic token). Discover ids via `list-relevant-people` or `microsoft-search-query`."
24973
24914
  },
24974
24915
  ...selectExpandOptions
@@ -25015,7 +24956,6 @@ var init_get_user_manager = __esm(() => {
25015
24956
  name: "user-id",
25016
24957
  key: "userId",
25017
24958
  required: true,
25018
- aliases: [{ name: "id", key: "id" }],
25019
24959
  description: "Azure AD user ID or UPN — typically the user's email address. Discover via `list-relevant-people` (relevance-ranked colleagues) or `microsoft-search-query --query <name>` (federated person search across the tenant directory)."
25020
24960
  },
25021
24961
  ...selectExpandOptions
@@ -25105,7 +25045,6 @@ var init_get_group = __esm(() => {
25105
25045
  name: "group-id",
25106
25046
  key: "groupId",
25107
25047
  required: true,
25108
- aliases: [{ name: "id", key: "id" }],
25109
25048
  description: "Azure AD group object ID. Use `list-groups` to find one."
25110
25049
  },
25111
25050
  ...selectExpandOptions
@@ -25140,7 +25079,6 @@ var init_list_group_members = __esm(() => {
25140
25079
  name: "group-id",
25141
25080
  key: "groupId",
25142
25081
  required: true,
25143
- aliases: [{ name: "id", key: "id" }],
25144
25082
  description: "Azure AD group object ID. Use `list-groups` to find one."
25145
25083
  },
25146
25084
  ...odataQueryOptions
@@ -25176,7 +25114,6 @@ var init_list_group_owners = __esm(() => {
25176
25114
  name: "group-id",
25177
25115
  key: "groupId",
25178
25116
  required: true,
25179
- aliases: [{ name: "id", key: "id" }],
25180
25117
  description: "Azure AD group object ID. Use `list-groups` to find one."
25181
25118
  },
25182
25119
  ...odataQueryOptions
@@ -25212,7 +25149,6 @@ var init_list_group_events = __esm(() => {
25212
25149
  name: "group-id",
25213
25150
  key: "groupId",
25214
25151
  required: true,
25215
- aliases: [{ name: "id", key: "id" }],
25216
25152
  description: "Azure AD group object ID for a unified (Microsoft 365) group. Use `list-groups` to find one."
25217
25153
  },
25218
25154
  ...odataQueryOptions
@@ -25249,17 +25185,15 @@ var init_get_group_calendar_view = __esm(() => {
25249
25185
  name: "group-id",
25250
25186
  key: "groupId",
25251
25187
  required: true,
25252
- aliases: [{ name: "id", key: "id" }],
25253
25188
  description: "Azure AD group object ID for a unified (Microsoft 365) group."
25254
25189
  },
25255
25190
  {
25256
25191
  name: "start-date-time",
25257
25192
  key: "startDateTime",
25258
25193
  required: true,
25259
- aliases: [{ name: "start", key: "start" }],
25260
25194
  description: `Start of the window (recurrences are expanded across it). ${RELATIVE_DATE_DESCRIPTION}`
25261
25195
  },
25262
- { name: "end-date-time", key: "endDateTime", required: true, aliases: [{ name: "end", key: "end" }], description: `End of the window. ${RELATIVE_DATE_DESCRIPTION}` },
25196
+ { name: "end-date-time", key: "endDateTime", required: true, description: `End of the window. ${RELATIVE_DATE_DESCRIPTION}` },
25263
25197
  ...odataQueryOptions
25264
25198
  ],
25265
25199
  example: "ask-marcel-office list-group-calendar-view --group-id 'a1b2c3d4-...' --start-date-time '2026-04-01T00:00:00Z' --end-date-time '2026-05-01T00:00:00Z'",
@@ -25293,7 +25227,6 @@ var init_list_group_conversations = __esm(() => {
25293
25227
  name: "group-id",
25294
25228
  key: "groupId",
25295
25229
  required: true,
25296
- aliases: [{ name: "id", key: "id" }],
25297
25230
  description: "Azure AD group object ID for a unified (Microsoft 365) group."
25298
25231
  },
25299
25232
  ...odataQueryOptions
@@ -25329,7 +25262,6 @@ var init_list_group_threads = __esm(() => {
25329
25262
  name: "group-id",
25330
25263
  key: "groupId",
25331
25264
  required: true,
25332
- aliases: [{ name: "id", key: "id" }],
25333
25265
  description: "Azure AD group object ID for a unified (Microsoft 365) group."
25334
25266
  },
25335
25267
  ...odataQueryOptions
@@ -25369,8 +25301,7 @@ var init_get_mail_message_mime = __esm(() => {
25369
25301
  name: "message-id",
25370
25302
  key: "messageId",
25371
25303
  required: true,
25372
- aliases: [{ name: "id", key: "id" }],
25373
- description: "Outlook message ID. Returned by `list-mail-messages` or `search-mail-messages`. Accepts `--id` as an alias."
25304
+ description: "Outlook message ID. Returned by `list-mail-messages` or `search-mail-messages`."
25374
25305
  }
25375
25306
  ],
25376
25307
  example: "ask-marcel-office get-mail-message-mime --message-id 'AAMkAD...'",
@@ -25386,15 +25317,23 @@ __export(exports_list_mail_folder_messages_delta, {
25386
25317
  meta: () => meta167,
25387
25318
  execute: () => execute165
25388
25319
  });
25389
- var baseSchema87, execute165, schema165, meta167;
25320
+ var schema165, execute165 = async (graph, params) => {
25321
+ const parsed = schema165.safeParse(params);
25322
+ if (!parsed.success)
25323
+ return err({ type: "validation_error", message: formatZodError(parsed.error) });
25324
+ const { mailFolderId, top, ...odata } = parsed.data;
25325
+ const headers = {};
25326
+ if (top !== undefined)
25327
+ headers["Prefer"] = `odata.maxpagesize=${top}`;
25328
+ return graph.get(appendOData(`/me/mailFolders/${mailFolderId}/messages/delta()`, odata), headers);
25329
+ }, meta167;
25390
25330
  var init_list_mail_folder_messages_delta = __esm(() => {
25391
25331
  init_zod();
25392
- init_build_command();
25332
+ init_format_zod_error();
25393
25333
  init_odata_query();
25394
- baseSchema87 = exports_external.object({ mailFolderId: exports_external.string().min(1) });
25395
- ({ execute: execute165, schema: schema165 } = buildListCommand((p) => `/me/mailFolders/${p.mailFolderId}/messages/delta()`, baseSchema87));
25334
+ schema165 = exports_external.object({ mailFolderId: exports_external.string().min(1) }).extend(pickODataShape(["top", "select", "filter", "expand"]));
25396
25335
  meta167 = {
25397
- summary: "Track incremental changes (added / updated / deleted messages) within a single mail folder using Microsoft Graph delta tokens. The first call returns the current snapshot plus a `@odata.deltaLink`; subsequent calls with that link return only what has changed since.",
25336
+ summary: 'Track incremental changes (added / updated / deleted messages) within a single mail folder using Microsoft Graph delta tokens. The first call returns the current snapshot plus a `@odata.deltaLink`; subsequent calls with that link return only what has changed since. `--top` is translated into the `Prefer: odata.maxpagesize=N` header: as a `$top` query parameter Graph reads a satisfied count as "sync complete" and hands back a deltaLink after N items, silently abandoning the rest of the folder. `$skip` and `$orderby` are NOT exposed — Graph ignores the former on this endpoint and rejects the latter unless it merely restates the default `receivedDateTime desc`.',
25398
25337
  category: "mail",
25399
25338
  graphMethod: "GET",
25400
25339
  graphPathTemplate: "/me/mailFolders/{mail-folder-id}/messages/delta()",
@@ -25404,15 +25343,14 @@ var init_list_mail_folder_messages_delta = __esm(() => {
25404
25343
  name: "mail-folder-id",
25405
25344
  key: "mailFolderId",
25406
25345
  required: true,
25407
- aliases: [{ name: "id", key: "id" }],
25408
25346
  description: "Mail folder ID or well-known name (`inbox`, `archive`, `sentitems`, `deleteditems`, `junkemail`, `drafts`). Returned by `list-mail-folders`."
25409
25347
  },
25410
- ...odataQueryOptions
25348
+ ...pickODataOptions(["top", "select", "filter", "expand"])
25411
25349
  ],
25412
25350
  example: "ask-marcel-office list-mail-folder-messages-delta --mail-folder-id 'inbox'",
25413
- responseShape: "collection of Microsoft Graph `message` resources under `data.value[]`. Cursor tokens are hoisted to envelope level: top-level `nextLink` while paging, then top-level `deltaLink` on the final page (CLI strips the original `@odata.*` keys from `data`).",
25351
+ responseShape: "collection of Microsoft Graph `message` resources under `data.value[]`. Cursor tokens are hoisted to envelope level: top-level `nextLink` while paging, then top-level `deltaLink` on the final page (CLI strips the original `@odata.*` keys from `data`). A `deltaLink` on the FIRST page means the folder is fully synced, not that it was truncated.",
25414
25352
  pagination: true,
25415
- paginationStrategy: "deltaLink"
25353
+ paginationStrategy: "preferMaxPageSize"
25416
25354
  };
25417
25355
  });
25418
25356
 
@@ -25423,13 +25361,13 @@ __export(exports_list_shared_mailbox_messages, {
25423
25361
  meta: () => meta168,
25424
25362
  execute: () => execute166
25425
25363
  });
25426
- var baseSchema88, execute166, schema166, meta168;
25364
+ var baseSchema87, execute166, schema166, meta168;
25427
25365
  var init_list_shared_mailbox_messages = __esm(() => {
25428
25366
  init_zod();
25429
25367
  init_build_command();
25430
25368
  init_odata_query();
25431
- baseSchema88 = exports_external.object({ userId: exports_external.string().min(1) });
25432
- ({ execute: execute166, schema: schema166 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/messages`, baseSchema88));
25369
+ baseSchema87 = exports_external.object({ userId: exports_external.string().min(1) });
25370
+ ({ execute: execute166, schema: schema166 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/messages`, baseSchema87));
25433
25371
  meta168 = {
25434
25372
  summary: "List messages from a shared or delegated mailbox the signed-in user has read access to. Same shape as `list-mail-messages` but scoped to a specific mailbox owner. 403 if the signed-in user does not have shared access to that mailbox.",
25435
25373
  category: "mail",
@@ -25441,7 +25379,6 @@ var init_list_shared_mailbox_messages = __esm(() => {
25441
25379
  name: "user-id",
25442
25380
  key: "userId",
25443
25381
  required: true,
25444
- aliases: [{ name: "id", key: "id" }],
25445
25382
  description: "Azure AD user ID or UPN of the shared mailbox or delegated user. The signed-in user must have `Mail.Read.Shared` access (granted by the mailbox owner)."
25446
25383
  },
25447
25384
  ...odataQueryOptions
@@ -25459,13 +25396,13 @@ __export(exports_list_shared_mailbox_folder_messages, {
25459
25396
  meta: () => meta169,
25460
25397
  execute: () => execute167
25461
25398
  });
25462
- var baseSchema89, execute167, schema167, meta169;
25399
+ var baseSchema88, execute167, schema167, meta169;
25463
25400
  var init_list_shared_mailbox_folder_messages = __esm(() => {
25464
25401
  init_zod();
25465
25402
  init_build_command();
25466
25403
  init_odata_query();
25467
- baseSchema89 = exports_external.object({ userId: exports_external.string().min(1), mailFolderId: exports_external.string().min(1) });
25468
- ({ execute: execute167, schema: schema167 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/mailFolders/${p.mailFolderId}/messages`, baseSchema89));
25404
+ baseSchema88 = exports_external.object({ userId: exports_external.string().min(1), mailFolderId: exports_external.string().min(1) });
25405
+ ({ execute: execute167, schema: schema167 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/mailFolders/${p.mailFolderId}/messages`, baseSchema88));
25469
25406
  meta169 = {
25470
25407
  summary: "List messages in a single folder of a shared / delegated mailbox.",
25471
25408
  category: "mail",
@@ -25500,13 +25437,13 @@ __export(exports_get_shared_mailbox_message, {
25500
25437
  meta: () => meta170,
25501
25438
  execute: () => execute168
25502
25439
  });
25503
- var baseSchema90, execute168, schema168, meta170;
25440
+ var baseSchema89, execute168, schema168, meta170;
25504
25441
  var init_get_shared_mailbox_message = __esm(() => {
25505
25442
  init_zod();
25506
25443
  init_build_command();
25507
25444
  init_odata_query();
25508
- baseSchema90 = exports_external.object({ userId: exports_external.string().min(1), messageId: exports_external.string().min(1) });
25509
- ({ execute: execute168, schema: schema168 } = buildSelectableCommand((p) => `/users/${encodeURIComponent(p.userId)}/messages/${p.messageId}`, baseSchema90));
25445
+ baseSchema89 = exports_external.object({ userId: exports_external.string().min(1), messageId: exports_external.string().min(1) });
25446
+ ({ execute: execute168, schema: schema168 } = buildSelectableCommand((p) => `/users/${encodeURIComponent(p.userId)}/messages/${p.messageId}`, baseSchema89));
25510
25447
  meta170 = {
25511
25448
  summary: "Return a single message from a shared / delegated mailbox. Use `--select` to fetch only specific fields (e.g. `--select id,subject,from,receivedDateTime`) — sibling to `get-mail-message` for /me.",
25512
25449
  category: "mail",
@@ -25565,7 +25502,6 @@ var init_list_conversation_messages = __esm(() => {
25565
25502
  name: "conversation-id",
25566
25503
  key: "conversationId",
25567
25504
  required: true,
25568
- aliases: [{ name: "id", key: "id" }],
25569
25505
  description: "Outlook `conversationId` of any message in the thread (returned by every mail-listing command and by `get-mail-message`)."
25570
25506
  },
25571
25507
  ...allowedOptions
@@ -25583,13 +25519,13 @@ __export(exports_list_focused_inbox_overrides, {
25583
25519
  meta: () => meta172,
25584
25520
  execute: () => execute170
25585
25521
  });
25586
- var baseSchema91, execute170, schema170, meta172;
25522
+ var baseSchema90, execute170, schema170, meta172;
25587
25523
  var init_list_focused_inbox_overrides = __esm(() => {
25588
25524
  init_zod();
25589
25525
  init_build_command();
25590
25526
  init_odata_query();
25591
- baseSchema91 = exports_external.object({}).strict();
25592
- ({ execute: execute170, schema: schema170 } = buildListCommand(() => "/me/inferenceClassification/overrides", baseSchema91));
25527
+ baseSchema90 = exports_external.object({}).strict();
25528
+ ({ execute: execute170, schema: schema170 } = buildListCommand(() => "/me/inferenceClassification/overrides", baseSchema90));
25593
25529
  meta172 = {
25594
25530
  summary: "List the signed-in user's Focused Inbox classification overrides — sender addresses they've manually moved to Focused or Other, which override Microsoft's automatic classifier.",
25595
25531
  category: "mail",
@@ -25635,13 +25571,13 @@ __export(exports_list_shared_calendar_events, {
25635
25571
  meta: () => meta174,
25636
25572
  execute: () => execute172
25637
25573
  });
25638
- var baseSchema92, execute172, schema172, meta174;
25574
+ var baseSchema91, execute172, schema172, meta174;
25639
25575
  var init_list_shared_calendar_events = __esm(() => {
25640
25576
  init_zod();
25641
25577
  init_build_command();
25642
25578
  init_odata_query();
25643
- baseSchema92 = exports_external.object({ userId: exports_external.string().min(1) });
25644
- ({ execute: execute172, schema: schema172 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/calendar/events`, baseSchema92));
25579
+ baseSchema91 = exports_external.object({ userId: exports_external.string().min(1) });
25580
+ ({ execute: execute172, schema: schema172 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/calendar/events`, baseSchema91));
25645
25581
  meta174 = {
25646
25582
  summary: "List events from another user's primary calendar (shared / delegated access). 403 without `Calendars.Read.Shared`.",
25647
25583
  category: "calendar",
@@ -25653,7 +25589,6 @@ var init_list_shared_calendar_events = __esm(() => {
25653
25589
  name: "user-id",
25654
25590
  key: "userId",
25655
25591
  required: true,
25656
- aliases: [{ name: "id", key: "id" }],
25657
25592
  description: "Azure AD user ID or UPN whose calendar to read. Requires `Calendars.Read.Shared` access (granted by the calendar owner)."
25658
25593
  },
25659
25594
  ...odataQueryOptions
@@ -25671,14 +25606,14 @@ __export(exports_get_shared_calendar_view, {
25671
25606
  meta: () => meta175,
25672
25607
  execute: () => execute173
25673
25608
  });
25674
- var baseSchema93, execute173, schema173, meta175;
25609
+ var baseSchema92, execute173, schema173, meta175;
25675
25610
  var init_get_shared_calendar_view = __esm(() => {
25676
25611
  init_zod();
25677
25612
  init_build_command();
25678
25613
  init_iso_datetime_schema();
25679
25614
  init_odata_query();
25680
- baseSchema93 = exports_external.object({ userId: exports_external.string().min(1), startDateTime: isoDateTimeField, endDateTime: isoDateTimeField });
25681
- ({ execute: execute173, schema: schema173 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/calendarView?startDateTime=${encodeURIComponent(p.startDateTime)}&endDateTime=${encodeURIComponent(p.endDateTime)}`, baseSchema93));
25615
+ baseSchema92 = exports_external.object({ userId: exports_external.string().min(1), startDateTime: isoDateTimeField, endDateTime: isoDateTimeField });
25616
+ ({ execute: execute173, schema: schema173 } = buildListCommand((p) => `/users/${encodeURIComponent(p.userId)}/calendarView?startDateTime=${encodeURIComponent(p.startDateTime)}&endDateTime=${encodeURIComponent(p.endDateTime)}`, baseSchema92));
25682
25617
  meta175 = {
25683
25618
  summary: "Return a date-windowed calendar view from another user's primary calendar (shared / delegated access). Recurrences expanded into individual occurrences.",
25684
25619
  category: "calendar",
@@ -25690,11 +25625,10 @@ var init_get_shared_calendar_view = __esm(() => {
25690
25625
  name: "user-id",
25691
25626
  key: "userId",
25692
25627
  required: true,
25693
- aliases: [{ name: "id", key: "id" }],
25694
25628
  description: "Azure AD user ID or UPN of the calendar owner."
25695
25629
  },
25696
- { name: "start-date-time", key: "startDateTime", required: true, aliases: [{ name: "start", key: "start" }], description: `Start of the window. ${RELATIVE_DATE_DESCRIPTION}` },
25697
- { name: "end-date-time", key: "endDateTime", required: true, aliases: [{ name: "end", key: "end" }], description: `End of the window. ${RELATIVE_DATE_DESCRIPTION}` },
25630
+ { name: "start-date-time", key: "startDateTime", required: true, description: `Start of the window. ${RELATIVE_DATE_DESCRIPTION}` },
25631
+ { name: "end-date-time", key: "endDateTime", required: true, description: `End of the window. ${RELATIVE_DATE_DESCRIPTION}` },
25698
25632
  ...odataQueryOptions
25699
25633
  ],
25700
25634
  example: "ask-marcel-office list-shared-calendar-view --user-id 'colleague@contoso.com' --start-date-time '2026-04-01T00:00:00Z' --end-date-time '2026-05-01T00:00:00Z'",
@@ -25710,13 +25644,13 @@ __export(exports_list_sharepoint_list_columns, {
25710
25644
  meta: () => meta176,
25711
25645
  execute: () => execute174
25712
25646
  });
25713
- var baseSchema94, execute174, schema174, meta176;
25647
+ var baseSchema93, execute174, schema174, meta176;
25714
25648
  var init_list_sharepoint_list_columns = __esm(() => {
25715
25649
  init_zod();
25716
25650
  init_build_command();
25717
25651
  init_odata_query();
25718
- baseSchema94 = exports_external.object({ siteId: exports_external.string().min(1), listId: exports_external.string().min(1) });
25719
- ({ execute: execute174, schema: schema174 } = buildSelectableCommand((p) => `/sites/${p.siteId}/lists/${p.listId}/columns`, baseSchema94));
25652
+ baseSchema93 = exports_external.object({ siteId: exports_external.string().min(1), listId: exports_external.string().min(1) });
25653
+ ({ execute: execute174, schema: schema174 } = buildSelectableCommand((p) => `/sites/${p.siteId}/lists/${p.listId}/columns`, baseSchema93));
25720
25654
  meta176 = {
25721
25655
  summary: "List the column definitions (schema) of a SharePoint list. Useful before reading list items so you know which fields exist and their types. Note: Graph silently ignores `$top` and `$skip` on this endpoint, so the CLI exposes only `--select` and `--expand`.",
25722
25656
  category: "sharepoint",
@@ -25750,13 +25684,13 @@ __export(exports_get_sharepoint_list_column, {
25750
25684
  meta: () => meta177,
25751
25685
  execute: () => execute175
25752
25686
  });
25753
- var baseSchema95, execute175, schema175, meta177;
25687
+ var baseSchema94, execute175, schema175, meta177;
25754
25688
  var init_get_sharepoint_list_column = __esm(() => {
25755
25689
  init_zod();
25756
25690
  init_build_command();
25757
25691
  init_odata_query();
25758
- baseSchema95 = exports_external.object({ siteId: exports_external.string().min(1), listId: exports_external.string().min(1), columnId: exports_external.string().min(1) });
25759
- ({ execute: execute175, schema: schema175 } = buildSelectableCommand((p) => `/sites/${p.siteId}/lists/${p.listId}/columns/${p.columnId}`, baseSchema95));
25692
+ baseSchema94 = exports_external.object({ siteId: exports_external.string().min(1), listId: exports_external.string().min(1), columnId: exports_external.string().min(1) });
25693
+ ({ execute: execute175, schema: schema175 } = buildSelectableCommand((p) => `/sites/${p.siteId}/lists/${p.listId}/columns/${p.columnId}`, baseSchema94));
25760
25694
  meta177 = {
25761
25695
  summary: "Return a single column definition from a SharePoint list.",
25762
25696
  category: "sharepoint",
@@ -25814,14 +25748,14 @@ __export(exports_list_sharepoint_site_onenote_notebooks, {
25814
25748
  meta: () => meta178,
25815
25749
  execute: () => execute176
25816
25750
  });
25817
- var baseSchema96, inner14, execute176, schema176, meta178;
25751
+ var baseSchema95, inner14, execute176, schema176, meta178;
25818
25752
  var init_list_sharepoint_site_onenote_notebooks = __esm(() => {
25819
25753
  init_zod();
25820
25754
  init_build_command();
25821
25755
  init_odata_query();
25822
25756
  init_onenote_5k_limit();
25823
- baseSchema96 = exports_external.object({ siteId: exports_external.string().min(1) });
25824
- inner14 = buildListCommand((p) => `/sites/${p.siteId}/onenote/notebooks`, baseSchema96);
25757
+ baseSchema95 = exports_external.object({ siteId: exports_external.string().min(1) });
25758
+ inner14 = buildListCommand((p) => `/sites/${p.siteId}/onenote/notebooks`, baseSchema95);
25825
25759
  execute176 = wrapOnenote5kLimit(inner14.execute);
25826
25760
  ({ schema: schema176 } = inner14);
25827
25761
  meta178 = {
@@ -25835,7 +25769,6 @@ var init_list_sharepoint_site_onenote_notebooks = __esm(() => {
25835
25769
  name: "site-id",
25836
25770
  key: "siteId",
25837
25771
  required: true,
25838
- aliases: [{ name: "id", key: "id" }],
25839
25772
  description: "SharePoint site ID."
25840
25773
  },
25841
25774
  ...odataQueryOptions
@@ -25853,14 +25786,14 @@ __export(exports_list_sharepoint_site_onenote_notebook_sections, {
25853
25786
  meta: () => meta179,
25854
25787
  execute: () => execute177
25855
25788
  });
25856
- var baseSchema97, inner15, execute177, schema177, meta179;
25789
+ var baseSchema96, inner15, execute177, schema177, meta179;
25857
25790
  var init_list_sharepoint_site_onenote_notebook_sections = __esm(() => {
25858
25791
  init_zod();
25859
25792
  init_build_command();
25860
25793
  init_odata_query();
25861
25794
  init_onenote_5k_limit();
25862
- baseSchema97 = exports_external.object({ siteId: exports_external.string().min(1), notebookId: exports_external.string().min(1) });
25863
- inner15 = buildListCommand((p) => `/sites/${p.siteId}/onenote/notebooks/${p.notebookId}/sections`, baseSchema97);
25795
+ baseSchema96 = exports_external.object({ siteId: exports_external.string().min(1), notebookId: exports_external.string().min(1) });
25796
+ inner15 = buildListCommand((p) => `/sites/${p.siteId}/onenote/notebooks/${p.notebookId}/sections`, baseSchema96);
25864
25797
  execute177 = wrapOnenote5kLimit(inner15.execute);
25865
25798
  ({ schema: schema177 } = inner15);
25866
25799
  meta179 = {
@@ -25897,14 +25830,14 @@ __export(exports_list_sharepoint_site_onenote_section_pages, {
25897
25830
  meta: () => meta180,
25898
25831
  execute: () => execute178
25899
25832
  });
25900
- var baseSchema98, inner16, execute178, schema178, meta180;
25833
+ var baseSchema97, inner16, execute178, schema178, meta180;
25901
25834
  var init_list_sharepoint_site_onenote_section_pages = __esm(() => {
25902
25835
  init_zod();
25903
25836
  init_build_command();
25904
25837
  init_odata_query();
25905
25838
  init_onenote_5k_limit();
25906
- baseSchema98 = exports_external.object({ siteId: exports_external.string().min(1), onenoteSectionId: exports_external.string().min(1) });
25907
- inner16 = buildListCommand((p) => `/sites/${p.siteId}/onenote/sections/${p.onenoteSectionId}/pages`, baseSchema98);
25839
+ baseSchema97 = exports_external.object({ siteId: exports_external.string().min(1), onenoteSectionId: exports_external.string().min(1) });
25840
+ inner16 = buildListCommand((p) => `/sites/${p.siteId}/onenote/sections/${p.onenoteSectionId}/pages`, baseSchema97);
25908
25841
  execute178 = wrapOnenote5kLimit(inner16.execute);
25909
25842
  ({ schema: schema178 } = inner16);
25910
25843
  meta180 = {
@@ -25924,8 +25857,7 @@ var init_list_sharepoint_site_onenote_section_pages = __esm(() => {
25924
25857
  name: "onenote-section-id",
25925
25858
  key: "onenoteSectionId",
25926
25859
  required: true,
25927
- description: "OneNote section ID inside the site.",
25928
- aliases: [{ name: "section-id", key: "sectionId" }]
25860
+ description: "OneNote section ID inside the site."
25929
25861
  },
25930
25862
  ...odataQueryOptions
25931
25863
  ],
@@ -25971,8 +25903,7 @@ var init_get_sharepoint_site_onenote_page_content = __esm(() => {
25971
25903
  name: "onenote-page-id",
25972
25904
  key: "onenotePageId",
25973
25905
  required: true,
25974
- description: "OneNote page ID inside the site.",
25975
- aliases: [{ name: "page-id", key: "pageId" }]
25906
+ description: "OneNote page ID inside the site."
25976
25907
  }
25977
25908
  ],
25978
25909
  example: "ask-marcel-office get-sharepoint-site-onenote-page-content --site-id 'contoso.sharepoint.com,...' --onenote-page-id 'p1'",
@@ -25988,14 +25919,14 @@ __export(exports_list_drive_item_thumbnails, {
25988
25919
  meta: () => meta182,
25989
25920
  execute: () => execute180
25990
25921
  });
25991
- var baseSchema99, execute180, schema180, meta182;
25922
+ var baseSchema98, execute180, schema180, meta182;
25992
25923
  var init_list_drive_item_thumbnails = __esm(() => {
25993
25924
  init_zod();
25994
25925
  init_build_command();
25995
25926
  init_odata_query();
25996
25927
  init_tenant_option();
25997
- baseSchema99 = exports_external.object({ driveId: exports_external.string().min(1), itemId: exports_external.string().min(1), ...tenantIdShape });
25998
- ({ execute: execute180, schema: schema180 } = buildNoSkipListCommand((p) => `/drives/${p.driveId}/items/${p.itemId}/thumbnails`, baseSchema99));
25928
+ baseSchema98 = exports_external.object({ driveId: exports_external.string().min(1), itemId: exports_external.string().min(1), ...tenantIdShape });
25929
+ ({ execute: execute180, schema: schema180 } = buildNoSkipListCommand((p) => `/drives/${p.driveId}/items/${p.itemId}/thumbnails`, baseSchema98));
25999
25930
  meta182 = {
26000
25931
  summary: "List thumbnail URLs (small / medium / large) for a OneDrive / SharePoint file. Each thumbnail set has pre-signed CDN URLs you can render in a UI without further auth.",
26001
25932
  category: "drive",
@@ -26130,13 +26061,13 @@ __export(exports_list_rooms, {
26130
26061
  meta: () => meta184,
26131
26062
  execute: () => execute182
26132
26063
  });
26133
- var baseSchema100, execute182, schema182, meta184;
26064
+ var baseSchema99, execute182, schema182, meta184;
26134
26065
  var init_list_rooms = __esm(() => {
26135
26066
  init_zod();
26136
26067
  init_build_command();
26137
26068
  init_odata_query();
26138
- baseSchema100 = exports_external.object({}).strict();
26139
- ({ execute: execute182, schema: schema182 } = buildListCommand(() => "/places/microsoft.graph.room", baseSchema100));
26069
+ baseSchema99 = exports_external.object({}).strict();
26070
+ ({ execute: execute182, schema: schema182 } = buildListCommand(() => "/places/microsoft.graph.room", baseSchema99));
26140
26071
  meta184 = {
26141
26072
  summary: "List bookable meeting rooms in the tenant. Each `room` has `displayName`, `emailAddress`, `capacity`, `building`, `floorNumber`, and `isWheelChairAccessible`. Use the `emailAddress` as a meeting `attendee` for room booking. Pass `--top 5` to limit the response — large tenants return tens of KB by default.",
26142
26073
  category: "calendar",
@@ -26157,13 +26088,13 @@ __export(exports_list_room_lists, {
26157
26088
  meta: () => meta185,
26158
26089
  execute: () => execute183
26159
26090
  });
26160
- var baseSchema101, execute183, schema183, meta185;
26091
+ var baseSchema100, execute183, schema183, meta185;
26161
26092
  var init_list_room_lists = __esm(() => {
26162
26093
  init_zod();
26163
26094
  init_build_command();
26164
26095
  init_odata_query();
26165
- baseSchema101 = exports_external.object({}).strict();
26166
- ({ execute: execute183, schema: schema183 } = buildListCommand(() => "/places/microsoft.graph.roomList", baseSchema101));
26096
+ baseSchema100 = exports_external.object({}).strict();
26097
+ ({ execute: execute183, schema: schema183 } = buildListCommand(() => "/places/microsoft.graph.roomList", baseSchema100));
26167
26098
  meta185 = {
26168
26099
  summary: "List room lists — usually one per building. Use these to scope a room search by location: a roomList groups the rooms in one office, then `/places/{roomList}/rooms` lists just those rooms. Pass `--top N` to limit the response on large tenants.",
26169
26100
  category: "calendar",
@@ -26184,13 +26115,13 @@ __export(exports_list_trending_insights, {
26184
26115
  meta: () => meta186,
26185
26116
  execute: () => execute184
26186
26117
  });
26187
- var baseSchema102, execute184, schema184, meta186;
26118
+ var baseSchema101, execute184, schema184, meta186;
26188
26119
  var init_list_trending_insights = __esm(() => {
26189
26120
  init_zod();
26190
26121
  init_build_command();
26191
26122
  init_odata_query();
26192
- baseSchema102 = exports_external.object({}).strict();
26193
- ({ execute: execute184, schema: schema184 } = buildListCommand(() => "/me/insights/trending", baseSchema102));
26123
+ baseSchema101 = exports_external.object({}).strict();
26124
+ ({ execute: execute184, schema: schema184 } = buildListCommand(() => "/me/insights/trending", baseSchema101));
26194
26125
  meta186 = {
26195
26126
  summary: "List documents trending around the signed-in user — files popular in their working network (colleagues' recent edits, shares, opens). Microsoft's relevance ranking, useful for surfacing unfamiliar but related work.",
26196
26127
  category: "drive",
@@ -26205,8 +26136,9 @@ var init_list_trending_insights = __esm(() => {
26205
26136
  });
26206
26137
 
26207
26138
  // src/use-cases/commands/index.ts
26208
- var commands;
26139
+ var modules, commands;
26209
26140
  var init_commands = __esm(() => {
26141
+ init_reject_unknown_params();
26210
26142
  init_download_drive_item_as_markdown();
26211
26143
  init_extract_drive_item_images();
26212
26144
  init_list_accessible_drives();
@@ -26391,7 +26323,7 @@ var init_commands = __esm(() => {
26391
26323
  init_list_rooms();
26392
26324
  init_list_room_lists();
26393
26325
  init_list_trending_insights();
26394
- commands = {
26326
+ modules = {
26395
26327
  "list-drives": exports_list_drives,
26396
26328
  "get-drive-root-item": exports_get_drive_root_item,
26397
26329
  "list-folder-files": exports_list_folder_files,
@@ -26577,6 +26509,7 @@ var init_commands = __esm(() => {
26577
26509
  "list-todo-tasks-delta": exports_list_todo_tasks_delta,
26578
26510
  "next-page": exports_next_page
26579
26511
  };
26512
+ commands = Object.fromEntries(Object.entries(modules).map(([name, command]) => [name, withUnknownParamRejection(command)]));
26580
26513
  });
26581
26514
 
26582
26515
  // node_modules/commander/lib/error.js
@@ -29021,7 +28954,17 @@ var init_output_text = __esm(() => {
29021
28954
  });
29022
28955
 
29023
28956
  // src/presenter/render-to-string.ts
29024
- var SIZE_HINT_THRESHOLD_BYTES = 50000, buildSizeHint = (bytes) => `Response is ${Math.round(bytes / 1024)} KB (> 50 KB threshold). Universal remedy: \`--output-path <file>\` writes bytes to disk and keeps the envelope compact (works on every command). Per-item slimming via \`--select id,subject,...\` and item-count reduction via \`--top N\` work ONLY when the command's \`--help\` advertises those flags endpoints like \`list-shared-with-me\`, \`microsoft-search-query\`, and the delta family silently ignore them.`, SELECT_HINT = "`value[]` contains entries but each is empty (only `@odata.etag`) likely caused by `--select` field names Graph did not recognise. Graph silently drops unknown `$select` fields; check spelling against the command's `responseShape` in `ask-marcel-office docs <command>`.", isPlainRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value), isMeaningfulKey = (key) => !key.startsWith("@odata."), looksLikeBogusSelectResponse = (data) => {
28957
+ var SIZE_HINT_THRESHOLD_BYTES = 50000, bytesRemedy = (context) => context.surface === "mcp" ? "Set the `outputPath` param to write the body to a file; the envelope then carries `savedTo` instead of the bytes." : "Write the body to a file with `--output-path <file>`; the envelope then carries `savedTo` instead of the bytes.", jsonRemedy = (context) => context.surface === "mcp" ? `${context.commandName} returns plain JSON, so \`outputPath\` is refused here: there is no body to write.` : `${context.commandName} returns plain JSON, so \`--output-path\` is refused; redirect to a file instead: \`ask-marcel-office ${context.commandName} ... > out.json\`.`, slimmingRemedy = (context) => {
28958
+ const levers = [...context.supportsSelect ? ["`--select id,subject,...` to slim each item"] : [], ...context.supportsTop ? ["`--top N` to cut the item count"] : []];
28959
+ if (levers.length === 0)
28960
+ return `${context.commandName} advertises no slimming flags, so narrow the query text itself and re-run.`;
28961
+ return `Then re-run with ${levers.join(" and ")}.`;
28962
+ }, NEUTRAL_REMEDY = "Narrow the request and re-run; slimming flags apply only where the command advertises them (check `--help`).", buildSizeHint = (bytes, context) => {
28963
+ const head = `Response is ${Math.round(bytes / 1024)} KB (> 50 KB threshold).`;
28964
+ if (context === undefined)
28965
+ return `${head} ${NEUTRAL_REMEDY}`;
28966
+ return `${head} ${context.producesBytes ? bytesRemedy(context) : jsonRemedy(context)} ${slimmingRemedy(context)}`;
28967
+ }, SELECT_HINT = "`value[]` contains entries but each is empty (only `@odata.etag`) — likely caused by `--select` field names Graph did not recognise. Graph silently drops unknown `$select` fields; check spelling against the command's `responseShape` in `ask-marcel-office docs <command>`.", isPlainRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value), isMeaningfulKey = (key) => !key.startsWith("@odata."), looksLikeBogusSelectResponse = (data) => {
29025
28968
  if (!isPlainRecord(data))
29026
28969
  return false;
29027
28970
  const value = data["value"];
@@ -29055,24 +28998,24 @@ var SIZE_HINT_THRESHOLD_BYTES = 50000, buildSizeHint = (bytes) => `Response is $
29055
28998
  ...typeof deltaLink === "string" ? { deltaLink: canonicalizeGraphCursor(deltaLink) } : {},
29056
28999
  ...typeof count === "number" ? { count } : {}
29057
29000
  };
29058
- }, renderJsonToString = (data) => {
29001
+ }, renderJsonToString = (data, context) => {
29059
29002
  const envelope = wrap(data);
29060
29003
  const selectHintField = looksLikeBogusSelectResponse(data) ? { selectHint: SELECT_HINT } : {};
29061
29004
  const initial = JSON.stringify({ ...envelope, ...selectHintField });
29062
29005
  if (initial.length <= SIZE_HINT_THRESHOLD_BYTES)
29063
29006
  return `${initial}
29064
29007
  `;
29065
- return `${JSON.stringify({ ...envelope, ...selectHintField, sizeHint: buildSizeHint(initial.length) })}
29008
+ return `${JSON.stringify({ ...envelope, ...selectHintField, sizeHint: buildSizeHint(initial.length, context) })}
29066
29009
  `;
29067
- }, renderTextToString = (data) => {
29010
+ }, renderTextToString = (data, context) => {
29068
29011
  const body = renderTextOutput(data);
29069
29012
  const selectHintLine = looksLikeBogusSelectResponse(data) ? `selectHint: ${SELECT_HINT}
29070
29013
  ` : "";
29071
29014
  if (body.length <= SIZE_HINT_THRESHOLD_BYTES)
29072
29015
  return `${selectHintLine}${body}`;
29073
- return `${selectHintLine}sizeHint: ${buildSizeHint(body.length)}
29016
+ return `${selectHintLine}sizeHint: ${buildSizeHint(body.length, context)}
29074
29017
  ${body}`;
29075
- }, renderToString = (data, format2) => format2 === "json" ? renderJsonToString(data) : renderTextToString(data), renderErrorToString = (message, format2, errorCode, explicitSource, retryAfterSeconds) => {
29018
+ }, renderToString = (data, format2, context) => format2 === "json" ? renderJsonToString(data, context) : renderTextToString(data, context), renderErrorToString = (message, format2, errorCode, explicitSource, retryAfterSeconds) => {
29076
29019
  const hint = findErrorHint(message, errorCode);
29077
29020
  const source = hint?.source ?? explicitSource;
29078
29021
  if (format2 === "json") {
@@ -29114,12 +29057,7 @@ var PAGINATION_HINT_NEXT_LINK = 'Paginated by Microsoft Graph. The CLI hoists `@
29114
29057
  if (strategy === "preferMaxPageSize")
29115
29058
  return PAGINATION_HINT_PREFER_MAX_PAGE_SIZE;
29116
29059
  return PAGINATION_HINT_NEXT_LINK;
29117
- }, CATEGORY_LABELS, CATEGORY_ORDER, renderAliasSuffix = (aliases) => {
29118
- if (!aliases || aliases.length === 0)
29119
- return "";
29120
- const names = aliases.map((a) => `\`--${a.name}\``).join(", ");
29121
- return ` _(aliases: ${names})_`;
29122
- }, renderCommandMarkdown = (entry) => {
29060
+ }, CATEGORY_LABELS, CATEGORY_ORDER, renderCommandMarkdown = (entry) => {
29123
29061
  const lines = [
29124
29062
  `# \`${entry.name}\``,
29125
29063
  "",
@@ -29129,10 +29067,6 @@ var PAGINATION_HINT_NEXT_LINK = 'Paginated by Microsoft Graph. The CLI hoists `@
29129
29067
  `- **Graph endpoint:** \`${entry.graphMethod} ${entry.graphPathTemplate}\``,
29130
29068
  `- **Microsoft Learn:** ${entry.graphDocsUrl}`
29131
29069
  ];
29132
- if (entry.commandAliases && entry.commandAliases.length > 0) {
29133
- const aliasNames = entry.commandAliases.map((a) => `\`${a}\``).join(", ");
29134
- lines.push(`- **Also invokable as (deprecated alias):** ${aliasNames}`);
29135
- }
29136
29070
  if (entry.responseShape)
29137
29071
  lines.push(`- **Response:** ${entry.responseShape}`);
29138
29072
  if (entry.pagination)
@@ -29157,7 +29091,7 @@ var PAGINATION_HINT_NEXT_LINK = 'Paginated by Microsoft Graph. The CLI hoists `@
29157
29091
  lines.push("", "## Options", "");
29158
29092
  lines.push("| Flag | Description |", "|------|-------------|");
29159
29093
  for (const o of entry.options)
29160
- lines.push(`| \`--${o.name}\` | ${o.description}${renderAliasSuffix(o.aliases)} |`);
29094
+ lines.push(`| \`--${o.name}\` | ${o.description} |`);
29161
29095
  }
29162
29096
  if (entry.bodyTemplate)
29163
29097
  lines.push("", "## Request body", "", "```json", entry.bodyTemplate, "```");
@@ -29388,7 +29322,6 @@ var toEntry = (name, cmd) => {
29388
29322
  name,
29389
29323
  summary: cmd.meta.summary,
29390
29324
  category: cmd.meta.category,
29391
- ...cmd.meta.commandAliases ? { commandAliases: cmd.meta.commandAliases } : {},
29392
29325
  graphMethod: cmd.meta.graphMethod,
29393
29326
  graphPathTemplate: cmd.meta.graphPathTemplate,
29394
29327
  graphDocsUrl: cmd.meta.graphDocsUrl,
@@ -29625,9 +29558,15 @@ var sourceFromGraphError = (error48) => {
29625
29558
  if (error48.type === "auth_failed")
29626
29559
  return "cli";
29627
29560
  return "graph";
29628
- }, bytesProducingCommands, mediaProducingCommands, formatOutputPathError = (error48, commandName) => {
29561
+ }, bytesProducingCommands, mediaProducingCommands, hasOption = (command, name) => command.meta.options.some((option) => option.name === name), buildSizeHintContext = (commandName, command, surface) => ({
29562
+ commandName,
29563
+ producesBytes: command.meta.producesBytes === true,
29564
+ supportsSelect: hasOption(command, "select"),
29565
+ supportsTop: hasOption(command, "top"),
29566
+ surface
29567
+ }), noBodyRemedy = (commandName, surface) => surface === "mcp" ? "Narrow the request instead (fewer items, a tighter query); there is no body to write." : `Plain JSON commands (list-*, get-*-user, get-organization, etc.) don't have a body to write — drop the flag and use a shell redirect instead: \`ask-marcel-office ${commandName} ... > out.json\`.`, formatOutputPathError = (error48, commandName, surface) => {
29629
29568
  if (error48.type === "no_inlined_bytes")
29630
- return `--output-path: ${commandName} did not return inlined bytes — this flag works only with commands that produce a body to write. Supported: ${bytesProducingCommands.join(", ")}. Plain JSON commands (list-*, get-*-user, get-organization, etc.) don't have a body to write — drop the flag and use a shell redirect instead: \`ask-marcel-office ${commandName} ... > out.json\`.`;
29569
+ return `--output-path: ${commandName} did not return inlined bytes — this flag works only with commands that produce a body to write. Supported: ${bytesProducingCommands.join(", ")}. ${noBodyRemedy(commandName, surface)}`;
29631
29570
  if (error48.type === "empty_path")
29632
29571
  return "--output-path: path argument is empty (likely a shell-quoting mistake — pass a real filesystem path)";
29633
29572
  if (error48.type === "is_directory")
@@ -29646,37 +29585,19 @@ var sourceFromGraphError = (error48) => {
29646
29585
  if (error48.type === "empty_path")
29647
29586
  return "--output-dir: directory argument is empty (likely a shell-quoting mistake — pass a real directory path)";
29648
29587
  return `--output-dir: write failed: ${error48.message}`;
29649
- }, normalizeAliases = (command, params) => {
29650
- const normalized = { ...params };
29651
- const aliasUsedFor = {};
29652
- for (const opt of command.meta.options) {
29653
- for (const alias of opt.aliases ?? []) {
29654
- const aliasValue = params[alias.key];
29655
- if (typeof aliasValue === "string" && !Object.hasOwn(params, opt.key)) {
29656
- normalized[opt.key] = aliasValue;
29657
- aliasUsedFor[opt.name] = alias.name;
29658
- }
29659
- }
29660
- }
29661
- return { normalized, aliasUsedFor };
29662
- }, toFailure = (command, error48, aliasUsedFor) => {
29663
- let message = error48.message;
29664
- for (const [canonical, alias] of Object.entries(aliasUsedFor)) {
29665
- message = message.replaceAll(`--${canonical}`, `--${alias}`);
29666
- }
29588
+ }, toFailure = (command, error48) => {
29667
29589
  const isLocalCommand = command.executeLocal !== undefined;
29668
29590
  return {
29669
- message,
29591
+ message: error48.message,
29670
29592
  ...error48.code === undefined ? {} : { code: error48.code },
29671
29593
  source: isLocalCommand && error48.type !== "validation_error" ? "cli" : sourceFromGraphError(error48),
29672
29594
  ...error48.type === "api_error" && error48.retryAfterSeconds !== undefined ? { retryAfterSeconds: error48.retryAfterSeconds } : {}
29673
29595
  };
29674
29596
  }, runRegistryCommand = async (deps, request) => {
29675
29597
  const { command, name } = request;
29676
- const { normalized, aliasUsedFor } = normalizeAliases(command, request.params);
29677
- const result = command.executeLocal !== undefined ? await command.executeLocal(deps.fs, normalized) : await command.execute(deps.graph, normalized);
29598
+ const result = command.executeLocal !== undefined ? await command.executeLocal(deps.fs, request.params) : await command.execute(deps.graph, request.params);
29678
29599
  if (!result.ok)
29679
- return err(toFailure(command, result.error, aliasUsedFor));
29600
+ return err(toFailure(command, result.error));
29680
29601
  if (request.outputDir !== undefined) {
29681
29602
  const persistedMedia = await persistMediaIfRequested(deps.fs, request.outputDir, result.value);
29682
29603
  if (persistedMedia.ok)
@@ -29686,7 +29607,7 @@ var sourceFromGraphError = (error48) => {
29686
29607
  const persisted = await persistIfRequested(deps.fs, request.outputPath, result.value);
29687
29608
  if (persisted.ok)
29688
29609
  return ok(persisted.value);
29689
- return err({ message: formatOutputPathError(persisted.error, name), code: persisted.error.type });
29610
+ return err({ message: formatOutputPathError(persisted.error, name, request.surface), code: persisted.error.type });
29690
29611
  };
29691
29612
  var init_run_registry_command = __esm(() => {
29692
29613
  init_commands();
@@ -44675,18 +44596,9 @@ var init_mcp = __esm(() => {
44675
44596
  });
44676
44597
 
44677
44598
  // src/use-cases/commands/resolve-command.ts
44678
- var findByAlias = (registry2, name) => {
44679
- for (const [canonical, command] of Object.entries(registry2)) {
44680
- if (command.meta.commandAliases?.includes(name))
44681
- return { name: canonical, command };
44682
- }
44683
- return;
44684
- }, availableNames = (registry2) => Object.entries(registry2).flatMap(([name, command]) => [name, ...command.meta.commandAliases ?? []]).toSorted((a, b) => a.localeCompare(b)), resolveCommand = (registry2, name) => {
44599
+ var availableNames = (registry2) => Object.keys(registry2).toSorted((a, b) => a.localeCompare(b)), resolveCommand = (registry2, name) => {
44685
44600
  if (Object.hasOwn(registry2, name))
44686
44601
  return ok({ name, command: registry2[name] });
44687
- const aliased = findByAlias(registry2, name);
44688
- if (aliased)
44689
- return ok(aliased);
44690
44602
  return err({ type: "unknown_command", name, available: availableNames(registry2) });
44691
44603
  };
44692
44604
  var init_resolve_command = () => {};
@@ -44723,7 +44635,7 @@ var PACKAGE_NAME = "ask-marcel-office-cli", okText = (text) => ({ content: [{ ty
44723
44635
  title: "Get command docs",
44724
44636
  description: "Full Markdown docs for ONE command: every option, its Graph endpoint, an example, and the response shape. Call this after list-commands and before run-command — it tells you exactly which params to pass. Also covers the lifecycle commands (login/logout/update/docs/help-json/mcp).",
44725
44637
  inputSchema: {
44726
- command: exports_external.string().describe("Command name, e.g. `list-mail-messages`. A deprecated former name also resolves.")
44638
+ command: exports_external.string().describe("Command name, e.g. `list-mail-messages`.")
44727
44639
  },
44728
44640
  annotations: { readOnlyHint: true, idempotentHint: true }
44729
44641
  }, async ({ command }) => {
@@ -44748,10 +44660,11 @@ var PACKAGE_NAME = "ask-marcel-office-cli", okText = (text) => ({ content: [{ ty
44748
44660
  return errText(`"${resolved.value.name}" writes to Microsoft 365, so it is not available through run-command (which is declared read-only). Use run-write-command instead. Write commands: ${writeCommandNames.join(", ")}.`);
44749
44661
  if (!isMutating && wantMutating)
44750
44662
  return errText(`"${resolved.value.name}" is a read command — use run-command. run-write-command only accepts: ${writeCommandNames.join(", ")}.`);
44751
- const result = await runRegistryCommand({ graph, fs }, { name: resolved.value.name, command: resolved.value.command, params: params ?? {}, outputPath, outputDir });
44663
+ const request = { name: resolved.value.name, command: resolved.value.command, params: params ?? {}, outputPath, outputDir, surface: "mcp" };
44664
+ const result = await runRegistryCommand({ graph, fs }, request);
44752
44665
  if (!result.ok)
44753
44666
  return errText(result.error.message, result.error.code, result.error.source, result.error.retryAfterSeconds);
44754
- return okText(renderToString(result.value, "text"));
44667
+ return okText(renderToString(result.value, "text", buildSizeHintContext(resolved.value.name, resolved.value.command, "mcp")));
44755
44668
  };
44756
44669
  server.registerTool("run-command", {
44757
44670
  title: "Run a read command",
@@ -44909,7 +44822,7 @@ import updateNotifier from "update-notifier";
44909
44822
  // package.json
44910
44823
  var package_default = {
44911
44824
  name: "ask-marcel-office-cli",
44912
- version: "2.2.0",
44825
+ version: "2.3.0",
44913
44826
  description: "Microsoft Graph CLI + library — typed Bun/TypeScript wrapper around 150+ Graph operations (read + on-the-fly PDF/markdown conversion + federated Microsoft Search) reachable from a Teams browser-OAuth token.",
44914
44827
  license: "MIT",
44915
44828
  author: "Vincent Delacourt <vincent.delacourt@adama-development.com>",
@@ -46943,9 +46856,9 @@ var {
46943
46856
 
46944
46857
  // src/presenter/output.ts
46945
46858
  init_render_to_string();
46946
- var render = (data, logger, format2) => {
46859
+ var render = (data, logger, format2, context) => {
46947
46860
  logger.info("output_rendered", {});
46948
- process.stdout.write(renderToString(data, format2));
46861
+ process.stdout.write(renderToString(data, format2, context));
46949
46862
  };
46950
46863
  var renderError = (message, format2, errorCode, explicitSource, retryAfterSeconds) => {
46951
46864
  process.stdout.write(renderErrorToString(message, format2, errorCode, explicitSource, retryAfterSeconds));
@@ -46999,7 +46912,7 @@ var buildCli = (deps) => {
46999
46912
  const raw = program2.opts().output;
47000
46913
  return raw === "json" ? "json" : "text";
47001
46914
  };
47002
- const renderOut = (data) => render(data, logger, getFormat());
46915
+ const renderOut = (data, sizeHintContext) => render(data, logger, getFormat(), sizeHintContext);
47003
46916
  const fail = (message, code, source, retryAfterSeconds) => {
47004
46917
  renderError(message, getFormat(), code, source, retryAfterSeconds);
47005
46918
  deps.onCommandError?.();
@@ -47016,7 +46929,7 @@ var buildCli = (deps) => {
47016
46929
  renderOut(persisted.value);
47017
46930
  return;
47018
46931
  }
47019
- fail(formatOutputPathError(persisted.error, commandName));
46932
+ fail(formatOutputPathError(persisted.error, commandName, "cli"));
47020
46933
  };
47021
46934
  program2.configureOutput({
47022
46935
  writeErr: () => {
@@ -47190,8 +47103,6 @@ var buildCli = (deps) => {
47190
47103
  program2.commandsGroup(`${CATEGORY_LABELS[category]}:`);
47191
47104
  for (const [name, cmd] of entries) {
47192
47105
  const commandDef = program2.command(name).description(cmd.meta.summary);
47193
- for (const aliasName of cmd.meta.commandAliases ?? [])
47194
- commandDef.alias(aliasName);
47195
47106
  const noRepeatParser = (flagName) => (value, previous) => {
47196
47107
  if (typeof previous === "string") {
47197
47108
  throw new InvalidArgumentError(`--${flagName} cannot be passed more than once (previous: "${previous}", new: "${value}"). Single-value flags reject duplicate occurrences.`);
@@ -47199,12 +47110,7 @@ var buildCli = (deps) => {
47199
47110
  return value;
47200
47111
  };
47201
47112
  for (const opt of cmd.meta.options) {
47202
- if (opt.aliases && opt.aliases.length > 0) {
47203
- commandDef.option(`--${opt.name} <value>`, opt.description, noRepeatParser(opt.name));
47204
- for (const alias of opt.aliases) {
47205
- commandDef.option(`--${alias.name} <value>`, `(alias for --${opt.name})`, noRepeatParser(alias.name));
47206
- }
47207
- } else if (opt.required) {
47113
+ if (opt.required) {
47208
47114
  commandDef.requiredOption(`--${opt.name} <value>`, opt.description, noRepeatParser(opt.name));
47209
47115
  } else {
47210
47116
  commandDef.option(`--${opt.name} <value>`, opt.description, noRepeatParser(opt.name));
@@ -47231,9 +47137,9 @@ Example:
47231
47137
  `));
47232
47138
  commandDef.action(async (opts) => {
47233
47139
  const globals = program2.opts();
47234
- const result = await runRegistryCommand({ graph, fs }, { name, command: cmd, params: opts, outputPath: globals.outputPath, outputDir: globals.outputDir });
47140
+ const result = await runRegistryCommand({ graph, fs }, { name, command: cmd, params: opts, outputPath: globals.outputPath, outputDir: globals.outputDir, surface: "cli" });
47235
47141
  if (result.ok) {
47236
- renderOut(result.value);
47142
+ renderOut(result.value, buildSizeHintContext(name, cmd, "cli"));
47237
47143
  return;
47238
47144
  }
47239
47145
  fail(result.error.message, result.error.code, result.error.source, result.error.retryAfterSeconds);