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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "package": "ask-marcel-office-cli",
3
- "version": "2.2.0",
4
- "generatedAt": "2026-07-19T12:40:32.946Z",
3
+ "version": "2.3.0",
4
+ "generatedAt": "2026-07-24T04:09:19.614Z",
5
5
  "commands": [
6
6
  {
7
7
  "name": "convert-calendar-event-attachment-to-markdown",
@@ -83,9 +83,6 @@
83
83
  "name": "convert-drive-item-zip-to-markdown",
84
84
  "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`.",
85
85
  "category": "drive",
86
- "commandAliases": [
87
- "convert-drive-item-zip"
88
- ],
89
86
  "graphMethod": "GET",
90
87
  "graphPathTemplate": "/drives/{drive-id}/items/{item-id}/content",
91
88
  "graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/driveitem-get-content",
@@ -142,9 +139,6 @@
142
139
  "name": "convert-local-file-to-markdown",
143
140
  "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.",
144
141
  "category": "meta",
145
- "commandAliases": [
146
- "convert-local-file"
147
- ],
148
142
  "graphMethod": "GET",
149
143
  "graphPathTemplate": "(local) reads {path} from the local filesystem; not a Graph endpoint",
150
144
  "graphDocsUrl": "https://learn.microsoft.com/en-us/graph/",
@@ -298,9 +292,6 @@
298
292
  "name": "convert-mail-attachment-zip-to-markdown",
299
293
  "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).",
300
294
  "category": "mail",
301
- "commandAliases": [
302
- "convert-mail-attachment-zip"
303
- ],
304
295
  "graphMethod": "GET",
305
296
  "graphPathTemplate": "/me/messages/{message-id}/attachments/{attachment-id}",
306
297
  "graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/attachment-get",
@@ -359,13 +350,7 @@
359
350
  "name": "message-id",
360
351
  "key": "messageId",
361
352
  "required": true,
362
- "aliases": [
363
- {
364
- "name": "id",
365
- "key": "id"
366
- }
367
- ],
368
- "description": "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
353
+ "description": "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`."
369
354
  },
370
355
  {
371
356
  "name": "inline-images",
@@ -403,13 +388,7 @@
403
388
  "name": "forward-message-id",
404
389
  "key": "forwardMessageId",
405
390
  "required": true,
406
- "aliases": [
407
- {
408
- "name": "id",
409
- "key": "id"
410
- }
411
- ],
412
- "description": "The message being forwarded. Source from list-mail-folder-messages or search-mail-messages. Accepts `--id` as an alias.",
391
+ "description": "The message being forwarded. Source from list-mail-folder-messages or search-mail-messages.",
413
392
  "argumentHint": {
414
393
  "kind": "idOrName"
415
394
  }
@@ -427,10 +406,10 @@
427
406
  "description": "Comma-separated list of CC recipient email addresses."
428
407
  },
429
408
  {
430
- "name": "body-content",
431
- "key": "bodyContent",
409
+ "name": "comment",
410
+ "key": "comment",
432
411
  "required": true,
433
- "description": "The comment text, placed above the quoted forwarded message. Plain text by default; pass --body-content-type HTML to send it as markup."
412
+ "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."
434
413
  },
435
414
  {
436
415
  "name": "subject",
@@ -442,7 +421,7 @@
442
421
  "name": "body-content-type",
443
422
  "key": "bodyContentType",
444
423
  "required": false,
445
- "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.",
424
+ "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.",
446
425
  "argumentHint": {
447
426
  "kind": "magicValue",
448
427
  "values": [
@@ -452,9 +431,9 @@
452
431
  }
453
432
  }
454
433
  ],
455
- "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.\"",
434
+ "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.\"",
456
435
  "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`.",
457
- "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}' }",
436
+ "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}' }",
458
437
  "mutates": true
459
438
  },
460
439
  {
@@ -549,28 +528,22 @@
549
528
  "name": "reply-to-message-id",
550
529
  "key": "replyToMessageId",
551
530
  "required": true,
552
- "aliases": [
553
- {
554
- "name": "id",
555
- "key": "id"
556
- }
557
- ],
558
- "description": "The message being replied to. Source from list-mail-folder-messages or search-mail-messages. Accepts `--id` as an alias.",
531
+ "description": "The message being replied to. Source from list-mail-folder-messages or search-mail-messages.",
559
532
  "argumentHint": {
560
533
  "kind": "idOrName"
561
534
  }
562
535
  },
563
536
  {
564
- "name": "body-content",
565
- "key": "bodyContent",
537
+ "name": "comment",
538
+ "key": "comment",
566
539
  "required": true,
567
- "description": "The reply text, placed above the quoted history. Plain text by default; pass --body-content-type HTML to send it as markup."
540
+ "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."
568
541
  },
569
542
  {
570
543
  "name": "body-content-type",
571
544
  "key": "bodyContentType",
572
545
  "required": false,
573
- "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.",
546
+ "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.",
574
547
  "argumentHint": {
575
548
  "kind": "magicValue",
576
549
  "values": [
@@ -599,9 +572,9 @@
599
572
  }
600
573
  }
601
574
  ],
602
- "example": "ask-marcel-office create-reply-draft --reply-to-message-id \"AAMkAD...\" --body-content \"Confirmed for Contoso, aligned with the group choice.\"",
575
+ "example": "ask-marcel-office create-reply-draft --reply-to-message-id \"AAMkAD...\" --comment \"Confirmed for Contoso, aligned with the group choice.\"",
603
576
  "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`.",
604
- "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}' }",
577
+ "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}' }",
605
578
  "mutates": true
606
579
  },
607
580
  {
@@ -715,9 +688,6 @@
715
688
  "name": "download-drive-item-content",
716
689
  "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.",
717
690
  "category": "drive",
718
- "commandAliases": [
719
- "download-onedrive-file-content"
720
- ],
721
691
  "graphMethod": "GET",
722
692
  "graphPathTemplate": "/drives/{drive-id}/items/{item-id}/content",
723
693
  "graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/driveitem-get-content",
@@ -915,13 +885,7 @@
915
885
  "name": "message-id",
916
886
  "key": "messageId",
917
887
  "required": true,
918
- "aliases": [
919
- {
920
- "name": "id",
921
- "key": "id"
922
- }
923
- ],
924
- "description": "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
888
+ "description": "Outlook message ID. Returned by `list-mail-messages` or `list-mail-folder-messages`."
925
889
  }
926
890
  ],
927
891
  "example": "ask-marcel-office extract-sharepoint-links-in-mail --message-id 'AAMkADk0...'",
@@ -995,12 +959,6 @@
995
959
  "name": "event-id",
996
960
  "key": "eventId",
997
961
  "required": true,
998
- "aliases": [
999
- {
1000
- "name": "id",
1001
- "key": "id"
1002
- }
1003
- ],
1004
962
  "description": "Microsoft Graph event ID. Returned by `ask-marcel-office list-calendar-events` in the `id` field of each event."
1005
963
  },
1006
964
  {
@@ -1067,12 +1025,6 @@
1067
1025
  "name": "chat-id",
1068
1026
  "key": "chatId",
1069
1027
  "required": true,
1070
- "aliases": [
1071
- {
1072
- "name": "id",
1073
- "key": "id"
1074
- }
1075
- ],
1076
1028
  "description": "Microsoft Teams chat ID, e.g. `19:abc...@thread.v2`. Returned by `list-chats`."
1077
1029
  },
1078
1030
  {
@@ -1134,13 +1086,7 @@
1134
1086
  "name": "item-id",
1135
1087
  "key": "itemId",
1136
1088
  "required": true,
1137
- "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).",
1138
- "aliases": [
1139
- {
1140
- "name": "folder-id",
1141
- "key": "folderId"
1142
- }
1143
- ]
1089
+ "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."
1144
1090
  },
1145
1091
  {
1146
1092
  "name": "top",
@@ -1154,18 +1100,6 @@
1154
1100
  "required": false,
1155
1101
  "description": "OData $select: comma-separated list of fields to include in each item (e.g. `id,subject,from`). May shrink payloads dramatically — Graph honors $select on most endpoints, but some collections (notably `/me/mailboxSettings`, `/me/outlook/masterCategories`, `/me/mailFolders/inbox/messageRules`) silently ignore it and always return the full resource. Bogus field names are silently dropped by Graph — if a field you asked for is missing from the response, double-check the spelling against the documented `responseShape`."
1156
1102
  },
1157
- {
1158
- "name": "filter",
1159
- "key": "filter",
1160
- "required": false,
1161
- "description": "OData $filter: predicate to narrow results server-side. Quoting rules: string literals MUST use SINGLE quotes (`subject eq 'invoice'`), NOT double quotes — Graph rejects `subject eq \"invoice\"` with `InvalidFilterClause`. To embed a single quote inside a string, double it (`subject eq 'O''Brien'`). Booleans, numbers, and dates are unquoted (`isRead eq false`, `receivedDateTime ge 2026-01-01T00:00:00Z`). Wrap the whole flag value in shell DOUBLE quotes so the inner single quotes survive (`--filter \"subject eq 'invoice'\"`). Same syntax Graph documents per resource type."
1162
- },
1163
- {
1164
- "name": "orderby",
1165
- "key": "orderby",
1166
- "required": false,
1167
- "description": "OData $orderby: sort expression with optional asc/desc (e.g. `receivedDateTime desc`). Some Graph filter combinations are rejected; remove $orderby if InefficientFilter occurs."
1168
- },
1169
1103
  {
1170
1104
  "name": "expand",
1171
1105
  "key": "expand",
@@ -1377,18 +1311,6 @@
1377
1311
  "required": false,
1378
1312
  "description": "OData $select: comma-separated list of fields to include in each item (e.g. `id,subject,from`). May shrink payloads dramatically — Graph honors $select on most endpoints, but some collections (notably `/me/mailboxSettings`, `/me/outlook/masterCategories`, `/me/mailFolders/inbox/messageRules`) silently ignore it and always return the full resource. Bogus field names are silently dropped by Graph — if a field you asked for is missing from the response, double-check the spelling against the documented `responseShape`."
1379
1313
  },
1380
- {
1381
- "name": "filter",
1382
- "key": "filter",
1383
- "required": false,
1384
- "description": "OData $filter: predicate to narrow results server-side. Quoting rules: string literals MUST use SINGLE quotes (`subject eq 'invoice'`), NOT double quotes — Graph rejects `subject eq \"invoice\"` with `InvalidFilterClause`. To embed a single quote inside a string, double it (`subject eq 'O''Brien'`). Booleans, numbers, and dates are unquoted (`isRead eq false`, `receivedDateTime ge 2026-01-01T00:00:00Z`). Wrap the whole flag value in shell DOUBLE quotes so the inner single quotes survive (`--filter \"subject eq 'invoice'\"`). Same syntax Graph documents per resource type."
1385
- },
1386
- {
1387
- "name": "orderby",
1388
- "key": "orderby",
1389
- "required": false,
1390
- "description": "OData $orderby: sort expression with optional asc/desc (e.g. `receivedDateTime desc`). Some Graph filter combinations are rejected; remove $orderby if InefficientFilter occurs."
1391
- },
1392
1314
  {
1393
1315
  "name": "expand",
1394
1316
  "key": "expand",
@@ -1412,12 +1334,6 @@
1412
1334
  "name": "drive-id",
1413
1335
  "key": "driveId",
1414
1336
  "required": true,
1415
- "aliases": [
1416
- {
1417
- "name": "id",
1418
- "key": "id"
1419
- }
1420
- ],
1421
1337
  "description": "Microsoft Graph drive ID. 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."
1422
1338
  },
1423
1339
  {
@@ -1638,12 +1554,6 @@
1638
1554
  "name": "group-id",
1639
1555
  "key": "groupId",
1640
1556
  "required": true,
1641
- "aliases": [
1642
- {
1643
- "name": "id",
1644
- "key": "id"
1645
- }
1646
- ],
1647
1557
  "description": "Azure AD group object ID. Use `list-groups` to find one."
1648
1558
  },
1649
1559
  {
@@ -1711,13 +1621,7 @@
1711
1621
  "name": "message-id",
1712
1622
  "key": "messageId",
1713
1623
  "required": true,
1714
- "aliases": [
1715
- {
1716
- "name": "id",
1717
- "key": "id"
1718
- }
1719
- ],
1720
- "description": "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
1624
+ "description": "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`."
1721
1625
  },
1722
1626
  {
1723
1627
  "name": "select",
@@ -1747,13 +1651,7 @@
1747
1651
  "name": "message-id",
1748
1652
  "key": "messageId",
1749
1653
  "required": true,
1750
- "aliases": [
1751
- {
1752
- "name": "id",
1753
- "key": "id"
1754
- }
1755
- ],
1756
- "description": "Outlook message ID. Returned by `list-mail-messages` or `search-mail-messages`. Accepts `--id` as an alias."
1654
+ "description": "Outlook message ID. Returned by `list-mail-messages` or `search-mail-messages`."
1757
1655
  }
1758
1656
  ],
1759
1657
  "example": "ask-marcel-office get-mail-message-mime --message-id 'AAMkAD...'",
@@ -1778,17 +1676,7 @@
1778
1676
  "name": "message-rule-id",
1779
1677
  "key": "messageRuleId",
1780
1678
  "required": true,
1781
- "description": "Message rule ID. Returned by `list-mail-rules`.",
1782
- "aliases": [
1783
- {
1784
- "name": "id",
1785
- "key": "id"
1786
- },
1787
- {
1788
- "name": "rule-id",
1789
- "key": "ruleId"
1790
- }
1791
- ]
1679
+ "description": "Message rule ID. Returned by `list-mail-rules`."
1792
1680
  }
1793
1681
  ],
1794
1682
  "example": "ask-marcel-office get-mail-rule --message-rule-id 'AQAAANC...'",
@@ -1806,13 +1694,7 @@
1806
1694
  "name": "message-id",
1807
1695
  "key": "messageId",
1808
1696
  "required": false,
1809
- "aliases": [
1810
- {
1811
- "name": "id",
1812
- "key": "id"
1813
- }
1814
- ],
1815
- "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.",
1697
+ "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.",
1816
1698
  "argumentHint": {
1817
1699
  "kind": "idOrName"
1818
1700
  }
@@ -1905,17 +1787,7 @@
1905
1787
  "name": "onenote-page-id",
1906
1788
  "key": "onenotePageId",
1907
1789
  "required": true,
1908
- "description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`.",
1909
- "aliases": [
1910
- {
1911
- "name": "id",
1912
- "key": "id"
1913
- },
1914
- {
1915
- "name": "page-id",
1916
- "key": "pageId"
1917
- }
1918
- ]
1790
+ "description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
1919
1791
  },
1920
1792
  {
1921
1793
  "name": "inline-images",
@@ -1960,17 +1832,7 @@
1960
1832
  "name": "onenote-page-id",
1961
1833
  "key": "onenotePageId",
1962
1834
  "required": true,
1963
- "description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`.",
1964
- "aliases": [
1965
- {
1966
- "name": "id",
1967
- "key": "id"
1968
- },
1969
- {
1970
- "name": "page-id",
1971
- "key": "pageId"
1972
- }
1973
- ]
1835
+ "description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
1974
1836
  }
1975
1837
  ],
1976
1838
  "example": "ask-marcel-office get-onenote-page-content --onenote-page-id '1-abc...'",
@@ -2013,17 +1875,7 @@
2013
1875
  "name": "planner-bucket-id",
2014
1876
  "key": "plannerBucketId",
2015
1877
  "required": true,
2016
- "description": "Planner bucket ID. Returned by `ask-marcel-office list-plan-buckets`.",
2017
- "aliases": [
2018
- {
2019
- "name": "id",
2020
- "key": "id"
2021
- },
2022
- {
2023
- "name": "bucket-id",
2024
- "key": "bucketId"
2025
- }
2026
- ]
1878
+ "description": "Planner bucket ID. Returned by `ask-marcel-office list-plan-buckets`."
2027
1879
  }
2028
1880
  ],
2029
1881
  "example": "ask-marcel-office get-planner-bucket --planner-bucket-id 'sFNeQRFu_kqhxpwwAhmA15gAGfoT'",
@@ -2041,17 +1893,7 @@
2041
1893
  "name": "planner-plan-id",
2042
1894
  "key": "plannerPlanId",
2043
1895
  "required": true,
2044
- "description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`.",
2045
- "aliases": [
2046
- {
2047
- "name": "id",
2048
- "key": "id"
2049
- },
2050
- {
2051
- "name": "plan-id",
2052
- "key": "planId"
2053
- }
2054
- ]
1896
+ "description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
2055
1897
  }
2056
1898
  ],
2057
1899
  "example": "ask-marcel-office get-planner-plan --planner-plan-id 'xqQg5FS2LkCp935s-FIFm5gAB6'",
@@ -2069,17 +1911,7 @@
2069
1911
  "name": "planner-task-id",
2070
1912
  "key": "plannerTaskId",
2071
1913
  "required": true,
2072
- "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).",
2073
- "aliases": [
2074
- {
2075
- "name": "id",
2076
- "key": "id"
2077
- },
2078
- {
2079
- "name": "task-id",
2080
- "key": "taskId"
2081
- }
2082
- ]
1914
+ "description": "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`."
2083
1915
  }
2084
1916
  ],
2085
1917
  "example": "ask-marcel-office get-planner-task --planner-task-id '01tx7Ic7-USXEwt0lvR1cmgAH8gK'",
@@ -2097,17 +1929,7 @@
2097
1929
  "name": "planner-task-id",
2098
1930
  "key": "plannerTaskId",
2099
1931
  "required": true,
2100
- "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).",
2101
- "aliases": [
2102
- {
2103
- "name": "id",
2104
- "key": "id"
2105
- },
2106
- {
2107
- "name": "task-id",
2108
- "key": "taskId"
2109
- }
2110
- ]
1932
+ "description": "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`."
2111
1933
  }
2112
1934
  ],
2113
1935
  "example": "ask-marcel-office get-planner-task-details --planner-task-id '01tx7Ic7-USXEwt0lvR1cmgAH8gK'",
@@ -2125,36 +1947,18 @@
2125
1947
  "name": "schedules",
2126
1948
  "key": "schedules",
2127
1949
  "required": true,
2128
- "aliases": [
2129
- {
2130
- "name": "emails",
2131
- "key": "emails"
2132
- }
2133
- ],
2134
1950
  "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`."
2135
1951
  },
2136
1952
  {
2137
1953
  "name": "start-date-time",
2138
1954
  "key": "startDateTime",
2139
1955
  "required": true,
2140
- "aliases": [
2141
- {
2142
- "name": "start",
2143
- "key": "start"
2144
- }
2145
- ],
2146
1956
  "description": "Window lower bound (interpreted as UTC). ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
2147
1957
  },
2148
1958
  {
2149
1959
  "name": "end-date-time",
2150
1960
  "key": "endDateTime",
2151
1961
  "required": true,
2152
- "aliases": [
2153
- {
2154
- "name": "end",
2155
- "key": "end"
2156
- }
2157
- ],
2158
1962
  "description": "Window upper bound (interpreted as UTC). Graph caps the span at 62 days. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
2159
1963
  },
2160
1964
  {
@@ -2261,12 +2065,6 @@
2261
2065
  "name": "site-id",
2262
2066
  "key": "siteId",
2263
2067
  "required": true,
2264
- "aliases": [
2265
- {
2266
- "name": "id",
2267
- "key": "id"
2268
- }
2269
- ],
2270
2068
  "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."
2271
2069
  },
2272
2070
  {
@@ -2411,13 +2209,7 @@
2411
2209
  "name": "list-item-id",
2412
2210
  "key": "listItemId",
2413
2211
  "required": true,
2414
- "description": "listItem ID (typically a small integer). Returned by `ask-marcel-office list-sharepoint-site-list-items`.",
2415
- "aliases": [
2416
- {
2417
- "name": "item-id",
2418
- "key": "itemId"
2419
- }
2420
- ]
2212
+ "description": "listItem ID (typically a small integer). Returned by `ask-marcel-office list-sharepoint-site-list-items`."
2421
2213
  },
2422
2214
  {
2423
2215
  "name": "select",
@@ -2453,13 +2245,7 @@
2453
2245
  "name": "onenote-page-id",
2454
2246
  "key": "onenotePageId",
2455
2247
  "required": true,
2456
- "description": "OneNote page ID inside the site.",
2457
- "aliases": [
2458
- {
2459
- "name": "page-id",
2460
- "key": "pageId"
2461
- }
2462
- ]
2248
+ "description": "OneNote page ID inside the site."
2463
2249
  }
2464
2250
  ],
2465
2251
  "example": "ask-marcel-office get-sharepoint-site-onenote-page-content --site-id 'contoso.sharepoint.com,...' --onenote-page-id 'p1'",
@@ -2478,12 +2264,6 @@
2478
2264
  "name": "site-id",
2479
2265
  "key": "siteId",
2480
2266
  "required": true,
2481
- "aliases": [
2482
- {
2483
- "name": "id",
2484
- "key": "id"
2485
- }
2486
- ],
2487
2267
  "description": "SharePoint site ID."
2488
2268
  }
2489
2269
  ],
@@ -2538,12 +2318,6 @@
2538
2318
  "name": "team-id",
2539
2319
  "key": "teamId",
2540
2320
  "required": true,
2541
- "aliases": [
2542
- {
2543
- "name": "id",
2544
- "key": "id"
2545
- }
2546
- ],
2547
2321
  "description": "Microsoft Teams team ID. Returned by `ask-marcel-office list-joined-teams`."
2548
2322
  },
2549
2323
  {
@@ -2610,12 +2384,6 @@
2610
2384
  "name": "team-id",
2611
2385
  "key": "teamId",
2612
2386
  "required": true,
2613
- "aliases": [
2614
- {
2615
- "name": "id",
2616
- "key": "id"
2617
- }
2618
- ],
2619
2387
  "description": "Microsoft Teams team ID. Returned by `list-joined-teams`."
2620
2388
  },
2621
2389
  {
@@ -2672,29 +2440,13 @@
2672
2440
  "name": "todo-task-list-id",
2673
2441
  "key": "todoTaskListId",
2674
2442
  "required": true,
2675
- "description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`.",
2676
- "aliases": [
2677
- {
2678
- "name": "task-list-id",
2679
- "key": "taskListId"
2680
- },
2681
- {
2682
- "name": "todo-list-id",
2683
- "key": "todoListId"
2684
- }
2685
- ]
2443
+ "description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
2686
2444
  },
2687
2445
  {
2688
2446
  "name": "todo-task-id",
2689
2447
  "key": "todoTaskId",
2690
2448
  "required": true,
2691
- "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).",
2692
- "aliases": [
2693
- {
2694
- "name": "task-id",
2695
- "key": "taskId"
2696
- }
2697
- ]
2449
+ "description": "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`."
2698
2450
  },
2699
2451
  {
2700
2452
  "name": "select",
@@ -2724,12 +2476,6 @@
2724
2476
  "name": "user-id",
2725
2477
  "key": "userId",
2726
2478
  "required": true,
2727
- "aliases": [
2728
- {
2729
- "name": "id",
2730
- "key": "id"
2731
- }
2732
- ],
2733
2479
  "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`."
2734
2480
  },
2735
2481
  {
@@ -2761,12 +2507,6 @@
2761
2507
  "name": "user-id",
2762
2508
  "key": "userId",
2763
2509
  "required": true,
2764
- "aliases": [
2765
- {
2766
- "name": "id",
2767
- "key": "id"
2768
- }
2769
- ],
2770
2510
  "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)."
2771
2511
  },
2772
2512
  {
@@ -2876,12 +2616,6 @@
2876
2616
  "name": "event-id",
2877
2617
  "key": "eventId",
2878
2618
  "required": true,
2879
- "aliases": [
2880
- {
2881
- "name": "id",
2882
- "key": "id"
2883
- }
2884
- ],
2885
2619
  "description": "Outlook calendar event ID. Returned by `ask-marcel-office list-calendar-events` or `get-calendar-event`."
2886
2620
  },
2887
2621
  {
@@ -2950,36 +2684,18 @@
2950
2684
  "name": "event-id",
2951
2685
  "key": "eventId",
2952
2686
  "required": true,
2953
- "aliases": [
2954
- {
2955
- "name": "id",
2956
- "key": "id"
2957
- }
2958
- ],
2959
2687
  "description": "Recurring event ID. Returned by `ask-marcel-office list-specific-calendar-events`."
2960
2688
  },
2961
2689
  {
2962
2690
  "name": "start-date-time",
2963
2691
  "key": "startDateTime",
2964
2692
  "required": true,
2965
- "aliases": [
2966
- {
2967
- "name": "start",
2968
- "key": "start"
2969
- }
2970
- ],
2971
2693
  "description": "Lower bound. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
2972
2694
  },
2973
2695
  {
2974
2696
  "name": "end-date-time",
2975
2697
  "key": "endDateTime",
2976
2698
  "required": true,
2977
- "aliases": [
2978
- {
2979
- "name": "end",
2980
- "key": "end"
2981
- }
2982
- ],
2983
2699
  "description": "Upper bound. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
2984
2700
  },
2985
2701
  {
@@ -3103,12 +2819,6 @@
3103
2819
  "name": "calendar-group-id",
3104
2820
  "key": "calendarGroupId",
3105
2821
  "required": true,
3106
- "aliases": [
3107
- {
3108
- "name": "id",
3109
- "key": "id"
3110
- }
3111
- ],
3112
2822
  "description": "Calendar group ID. Returned by `list-calendar-groups`."
3113
2823
  },
3114
2824
  {
@@ -3213,24 +2923,12 @@
3213
2923
  "name": "start-date-time",
3214
2924
  "key": "startDateTime",
3215
2925
  "required": true,
3216
- "aliases": [
3217
- {
3218
- "name": "start",
3219
- "key": "start"
3220
- }
3221
- ],
3222
2926
  "description": "Lower bound. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
3223
2927
  },
3224
2928
  {
3225
2929
  "name": "end-date-time",
3226
2930
  "key": "endDateTime",
3227
2931
  "required": true,
3228
- "aliases": [
3229
- {
3230
- "name": "end",
3231
- "key": "end"
3232
- }
3233
- ],
3234
2932
  "description": "Upper bound. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
3235
2933
  },
3236
2934
  {
@@ -3285,24 +2983,12 @@
3285
2983
  "name": "start-date-time",
3286
2984
  "key": "startDateTime",
3287
2985
  "required": true,
3288
- "aliases": [
3289
- {
3290
- "name": "start",
3291
- "key": "start"
3292
- }
3293
- ],
3294
2986
  "description": "Lower bound (required on the first call only — the deltaLink token encodes it for resumes). ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
3295
2987
  },
3296
2988
  {
3297
2989
  "name": "end-date-time",
3298
2990
  "key": "endDateTime",
3299
2991
  "required": true,
3300
- "aliases": [
3301
- {
3302
- "name": "end",
3303
- "key": "end"
3304
- }
3305
- ],
3306
2992
  "description": "Upper bound (required on the first call only — the deltaLink token encodes it for resumes). ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
3307
2993
  },
3308
2994
  {
@@ -3377,12 +3063,6 @@
3377
3063
  "name": "chat-id",
3378
3064
  "key": "chatId",
3379
3065
  "required": true,
3380
- "aliases": [
3381
- {
3382
- "name": "id",
3383
- "key": "id"
3384
- }
3385
- ],
3386
3066
  "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`."
3387
3067
  },
3388
3068
  {
@@ -3458,12 +3138,6 @@
3458
3138
  "name": "conversation-id",
3459
3139
  "key": "conversationId",
3460
3140
  "required": true,
3461
- "aliases": [
3462
- {
3463
- "name": "id",
3464
- "key": "id"
3465
- }
3466
- ],
3467
3141
  "description": "Outlook `conversationId` of any message in the thread (returned by every mail-listing command and by `get-mail-message`)."
3468
3142
  },
3469
3143
  {
@@ -4203,13 +3877,7 @@
4203
3877
  "name": "item-id",
4204
3878
  "key": "itemId",
4205
3879
  "required": true,
4206
- "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\".",
4207
- "aliases": [
4208
- {
4209
- "name": "folder-id",
4210
- "key": "folderId"
4211
- }
4212
- ]
3880
+ "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."
4213
3881
  },
4214
3882
  {
4215
3883
  "name": "top",
@@ -4307,36 +3975,18 @@
4307
3975
  "name": "group-id",
4308
3976
  "key": "groupId",
4309
3977
  "required": true,
4310
- "aliases": [
4311
- {
4312
- "name": "id",
4313
- "key": "id"
4314
- }
4315
- ],
4316
3978
  "description": "Azure AD group object ID for a unified (Microsoft 365) group."
4317
3979
  },
4318
3980
  {
4319
3981
  "name": "start-date-time",
4320
3982
  "key": "startDateTime",
4321
3983
  "required": true,
4322
- "aliases": [
4323
- {
4324
- "name": "start",
4325
- "key": "start"
4326
- }
4327
- ],
4328
3984
  "description": "Start of the window (recurrences are expanded across it). ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
4329
3985
  },
4330
3986
  {
4331
3987
  "name": "end-date-time",
4332
3988
  "key": "endDateTime",
4333
3989
  "required": true,
4334
- "aliases": [
4335
- {
4336
- "name": "end",
4337
- "key": "end"
4338
- }
4339
- ],
4340
3990
  "description": "End of the window. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
4341
3991
  },
4342
3992
  {
@@ -4392,12 +4042,6 @@
4392
4042
  "name": "group-id",
4393
4043
  "key": "groupId",
4394
4044
  "required": true,
4395
- "aliases": [
4396
- {
4397
- "name": "id",
4398
- "key": "id"
4399
- }
4400
- ],
4401
4045
  "description": "Azure AD group object ID for a unified (Microsoft 365) group."
4402
4046
  },
4403
4047
  {
@@ -4453,12 +4097,6 @@
4453
4097
  "name": "group-id",
4454
4098
  "key": "groupId",
4455
4099
  "required": true,
4456
- "aliases": [
4457
- {
4458
- "name": "id",
4459
- "key": "id"
4460
- }
4461
- ],
4462
4100
  "description": "Azure AD group object ID for a unified (Microsoft 365) group. Use `list-groups` to find one."
4463
4101
  },
4464
4102
  {
@@ -4514,12 +4152,6 @@
4514
4152
  "name": "group-id",
4515
4153
  "key": "groupId",
4516
4154
  "required": true,
4517
- "aliases": [
4518
- {
4519
- "name": "id",
4520
- "key": "id"
4521
- }
4522
- ],
4523
4155
  "description": "Azure AD group object ID. Use `list-groups` to find one."
4524
4156
  },
4525
4157
  {
@@ -4575,12 +4207,6 @@
4575
4207
  "name": "group-id",
4576
4208
  "key": "groupId",
4577
4209
  "required": true,
4578
- "aliases": [
4579
- {
4580
- "name": "id",
4581
- "key": "id"
4582
- }
4583
- ],
4584
4210
  "description": "Azure AD group object ID. Use `list-groups` to find one."
4585
4211
  },
4586
4212
  {
@@ -4636,12 +4262,6 @@
4636
4262
  "name": "group-id",
4637
4263
  "key": "groupId",
4638
4264
  "required": true,
4639
- "aliases": [
4640
- {
4641
- "name": "id",
4642
- "key": "id"
4643
- }
4644
- ],
4645
4265
  "description": "Azure AD group object ID for a unified (Microsoft 365) group."
4646
4266
  },
4647
4267
  {
@@ -4789,21 +4409,7 @@
4789
4409
  "name": "todo-task-list-id",
4790
4410
  "key": "todoTaskListId",
4791
4411
  "required": true,
4792
- "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.",
4793
- "aliases": [
4794
- {
4795
- "name": "id",
4796
- "key": "id"
4797
- },
4798
- {
4799
- "name": "task-list-id",
4800
- "key": "taskListId"
4801
- },
4802
- {
4803
- "name": "todo-list-id",
4804
- "key": "todoListId"
4805
- }
4806
- ]
4412
+ "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."
4807
4413
  },
4808
4414
  {
4809
4415
  "name": "top",
@@ -4870,13 +4476,7 @@
4870
4476
  "name": "message-id",
4871
4477
  "key": "messageId",
4872
4478
  "required": true,
4873
- "aliases": [
4874
- {
4875
- "name": "id",
4876
- "key": "id"
4877
- }
4878
- ],
4879
- "description": "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`. Accepts `--id` as an alias."
4479
+ "description": "Outlook message ID. Returned by `ask-marcel-office list-mail-messages` or `list-mail-folder-messages`."
4880
4480
  },
4881
4481
  {
4882
4482
  "name": "top",
@@ -4931,12 +4531,6 @@
4931
4531
  "name": "mail-folder-id",
4932
4532
  "key": "mailFolderId",
4933
4533
  "required": true,
4934
- "aliases": [
4935
- {
4936
- "name": "id",
4937
- "key": "id"
4938
- }
4939
- ],
4940
4534
  "description": "mailFolder ID. Returned by `ask-marcel-office list-mail-folders`. Well-known names also work, e.g. `inbox`, `sentitems`, `drafts`."
4941
4535
  },
4942
4536
  {
@@ -4992,12 +4586,6 @@
4992
4586
  "name": "mail-folder-id",
4993
4587
  "key": "mailFolderId",
4994
4588
  "required": true,
4995
- "aliases": [
4996
- {
4997
- "name": "id",
4998
- "key": "id"
4999
- }
5000
- ],
5001
4589
  "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."
5002
4590
  },
5003
4591
  {
@@ -5043,7 +4631,7 @@
5043
4631
  },
5044
4632
  {
5045
4633
  "name": "list-mail-folder-messages-delta",
5046
- "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.",
4634
+ "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`.",
5047
4635
  "category": "mail",
5048
4636
  "graphMethod": "GET",
5049
4637
  "graphPathTemplate": "/me/mailFolders/{mail-folder-id}/messages/delta()",
@@ -5053,12 +4641,6 @@
5053
4641
  "name": "mail-folder-id",
5054
4642
  "key": "mailFolderId",
5055
4643
  "required": true,
5056
- "aliases": [
5057
- {
5058
- "name": "id",
5059
- "key": "id"
5060
- }
5061
- ],
5062
4644
  "description": "Mail folder ID or well-known name (`inbox`, `archive`, `sentitems`, `deleteditems`, `junkemail`, `drafts`). Returned by `list-mail-folders`."
5063
4645
  },
5064
4646
  {
@@ -5067,12 +4649,6 @@
5067
4649
  "required": false,
5068
4650
  "description": "OData $top: maximum number of items to return on this page (positive integer, ≤ 1000). Graph silently caps at 1000 on every collection endpoint, so the CLI rejects larger values with a clear validation error rather than letting the request silently truncate. Combine with `next-page` to paginate beyond the cap."
5069
4651
  },
5070
- {
5071
- "name": "skip",
5072
- "key": "skip",
5073
- "required": false,
5074
- "description": "OData $skip: skip the first N items before returning results (non-negative integer). Useful with $top for offset paging."
5075
- },
5076
4652
  {
5077
4653
  "name": "select",
5078
4654
  "key": "select",
@@ -5085,12 +4661,6 @@
5085
4661
  "required": false,
5086
4662
  "description": "OData $filter: predicate to narrow results server-side. Quoting rules: string literals MUST use SINGLE quotes (`subject eq 'invoice'`), NOT double quotes — Graph rejects `subject eq \"invoice\"` with `InvalidFilterClause`. To embed a single quote inside a string, double it (`subject eq 'O''Brien'`). Booleans, numbers, and dates are unquoted (`isRead eq false`, `receivedDateTime ge 2026-01-01T00:00:00Z`). Wrap the whole flag value in shell DOUBLE quotes so the inner single quotes survive (`--filter \"subject eq 'invoice'\"`). Same syntax Graph documents per resource type."
5087
4663
  },
5088
- {
5089
- "name": "orderby",
5090
- "key": "orderby",
5091
- "required": false,
5092
- "description": "OData $orderby: sort expression with optional asc/desc (e.g. `receivedDateTime desc`). Some Graph filter combinations are rejected; remove $orderby if InefficientFilter occurs."
5093
- },
5094
4664
  {
5095
4665
  "name": "expand",
5096
4666
  "key": "expand",
@@ -5099,7 +4669,7 @@
5099
4669
  }
5100
4670
  ],
5101
4671
  "example": "ask-marcel-office list-mail-folder-messages-delta --mail-folder-id 'inbox'",
5102
- "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`).",
4672
+ "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.",
5103
4673
  "pagination": true
5104
4674
  },
5105
4675
  {
@@ -5389,12 +4959,6 @@
5389
4959
  "name": "notebook-id",
5390
4960
  "key": "notebookId",
5391
4961
  "required": true,
5392
- "aliases": [
5393
- {
5394
- "name": "id",
5395
- "key": "id"
5396
- }
5397
- ],
5398
4962
  "description": "OneNote notebook ID. Returned by `ask-marcel-office list-onenote-notebooks`."
5399
4963
  },
5400
4964
  {
@@ -5499,17 +5063,7 @@
5499
5063
  "name": "onenote-section-id",
5500
5064
  "key": "onenoteSectionId",
5501
5065
  "required": true,
5502
- "description": "OneNote section ID. Returned by `ask-marcel-office list-onenote-notebook-sections` or `list-all-onenote-sections`.",
5503
- "aliases": [
5504
- {
5505
- "name": "id",
5506
- "key": "id"
5507
- },
5508
- {
5509
- "name": "section-id",
5510
- "key": "sectionId"
5511
- }
5512
- ]
5066
+ "description": "OneNote section ID. Returned by `ask-marcel-office list-onenote-notebook-sections` or `list-all-onenote-sections`."
5513
5067
  },
5514
5068
  {
5515
5069
  "name": "top",
@@ -5575,17 +5129,7 @@
5575
5129
  "name": "planner-plan-id",
5576
5130
  "key": "plannerPlanId",
5577
5131
  "required": true,
5578
- "description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`.",
5579
- "aliases": [
5580
- {
5581
- "name": "id",
5582
- "key": "id"
5583
- },
5584
- {
5585
- "name": "plan-id",
5586
- "key": "planId"
5587
- }
5588
- ]
5132
+ "description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
5589
5133
  },
5590
5134
  {
5591
5135
  "name": "select",
@@ -5610,17 +5154,7 @@
5610
5154
  "name": "planner-plan-id",
5611
5155
  "key": "plannerPlanId",
5612
5156
  "required": true,
5613
- "description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`.",
5614
- "aliases": [
5615
- {
5616
- "name": "id",
5617
- "key": "id"
5618
- },
5619
- {
5620
- "name": "plan-id",
5621
- "key": "planId"
5622
- }
5623
- ]
5157
+ "description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
5624
5158
  }
5625
5159
  ],
5626
5160
  "example": "ask-marcel-office list-plan-tasks --planner-plan-id 'xqQg5FS2LkCp935s-FIFm5gAB6'",
@@ -5995,12 +5529,6 @@
5995
5529
  "name": "user-id",
5996
5530
  "key": "userId",
5997
5531
  "required": true,
5998
- "aliases": [
5999
- {
6000
- "name": "id",
6001
- "key": "id"
6002
- }
6003
- ],
6004
5532
  "description": "Azure AD user ID or UPN whose calendar to read. Requires `Calendars.Read.Shared` access (granted by the calendar owner)."
6005
5533
  },
6006
5534
  {
@@ -6056,36 +5584,18 @@
6056
5584
  "name": "user-id",
6057
5585
  "key": "userId",
6058
5586
  "required": true,
6059
- "aliases": [
6060
- {
6061
- "name": "id",
6062
- "key": "id"
6063
- }
6064
- ],
6065
5587
  "description": "Azure AD user ID or UPN of the calendar owner."
6066
5588
  },
6067
5589
  {
6068
5590
  "name": "start-date-time",
6069
5591
  "key": "startDateTime",
6070
5592
  "required": true,
6071
- "aliases": [
6072
- {
6073
- "name": "start",
6074
- "key": "start"
6075
- }
6076
- ],
6077
5593
  "description": "Start of the window. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
6078
5594
  },
6079
5595
  {
6080
5596
  "name": "end-date-time",
6081
5597
  "key": "endDateTime",
6082
5598
  "required": true,
6083
- "aliases": [
6084
- {
6085
- "name": "end",
6086
- "key": "end"
6087
- }
6088
- ],
6089
5599
  "description": "End of the window. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
6090
5600
  },
6091
5601
  {
@@ -6251,12 +5761,6 @@
6251
5761
  "name": "user-id",
6252
5762
  "key": "userId",
6253
5763
  "required": true,
6254
- "aliases": [
6255
- {
6256
- "name": "id",
6257
- "key": "id"
6258
- }
6259
- ],
6260
5764
  "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)."
6261
5765
  },
6262
5766
  {
@@ -6371,13 +5875,7 @@
6371
5875
  "name": "list-item-id",
6372
5876
  "key": "listItemId",
6373
5877
  "required": true,
6374
- "description": "List item ID inside the list. Returned by `list-sharepoint-site-list-items`.",
6375
- "aliases": [
6376
- {
6377
- "name": "item-id",
6378
- "key": "itemId"
6379
- }
6380
- ]
5878
+ "description": "List item ID inside the list. Returned by `list-sharepoint-site-list-items`."
6381
5879
  },
6382
5880
  {
6383
5881
  "name": "top",
@@ -6426,12 +5924,6 @@
6426
5924
  "name": "site-id",
6427
5925
  "key": "siteId",
6428
5926
  "required": true,
6429
- "aliases": [
6430
- {
6431
- "name": "id",
6432
- "key": "id"
6433
- }
6434
- ],
6435
5927
  "description": "SharePoint site ID. Returned by `ask-marcel-office search-sharepoint-sites-by-name`."
6436
5928
  },
6437
5929
  {
@@ -6539,12 +6031,6 @@
6539
6031
  "name": "site-id",
6540
6032
  "key": "siteId",
6541
6033
  "required": true,
6542
- "aliases": [
6543
- {
6544
- "name": "id",
6545
- "key": "id"
6546
- }
6547
- ],
6548
6034
  "description": "SharePoint site ID. Returned by `ask-marcel-office search-sharepoint-sites-by-name`."
6549
6035
  },
6550
6036
  {
@@ -6655,12 +6141,6 @@
6655
6141
  "name": "site-id",
6656
6142
  "key": "siteId",
6657
6143
  "required": true,
6658
- "aliases": [
6659
- {
6660
- "name": "id",
6661
- "key": "id"
6662
- }
6663
- ],
6664
6144
  "description": "SharePoint site ID."
6665
6145
  },
6666
6146
  {
@@ -6722,13 +6202,7 @@
6722
6202
  "name": "onenote-section-id",
6723
6203
  "key": "onenoteSectionId",
6724
6204
  "required": true,
6725
- "description": "OneNote section ID inside the site.",
6726
- "aliases": [
6727
- {
6728
- "name": "section-id",
6729
- "key": "sectionId"
6730
- }
6731
- ]
6205
+ "description": "OneNote section ID inside the site."
6732
6206
  },
6733
6207
  {
6734
6208
  "name": "top",
@@ -6783,12 +6257,6 @@
6783
6257
  "name": "site-id",
6784
6258
  "key": "siteId",
6785
6259
  "required": true,
6786
- "aliases": [
6787
- {
6788
- "name": "id",
6789
- "key": "id"
6790
- }
6791
- ],
6792
6260
  "description": "SharePoint site ID."
6793
6261
  },
6794
6262
  {
@@ -6838,12 +6306,6 @@
6838
6306
  "name": "site-id",
6839
6307
  "key": "siteId",
6840
6308
  "required": true,
6841
- "aliases": [
6842
- {
6843
- "name": "id",
6844
- "key": "id"
6845
- }
6846
- ],
6847
6309
  "description": "SharePoint site ID. Returned by `search-sharepoint-sites-by-name`."
6848
6310
  },
6849
6311
  {
@@ -6874,12 +6336,6 @@
6874
6336
  "name": "site-id",
6875
6337
  "key": "siteId",
6876
6338
  "required": true,
6877
- "aliases": [
6878
- {
6879
- "name": "id",
6880
- "key": "id"
6881
- }
6882
- ],
6883
6339
  "description": "SharePoint site ID."
6884
6340
  },
6885
6341
  {
@@ -6929,12 +6385,6 @@
6929
6385
  "name": "calendar-id",
6930
6386
  "key": "calendarId",
6931
6387
  "required": true,
6932
- "aliases": [
6933
- {
6934
- "name": "id",
6935
- "key": "id"
6936
- }
6937
- ],
6938
6388
  "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."
6939
6389
  },
6940
6390
  {
@@ -6990,36 +6440,18 @@
6990
6440
  "name": "calendar-id",
6991
6441
  "key": "calendarId",
6992
6442
  "required": true,
6993
- "aliases": [
6994
- {
6995
- "name": "id",
6996
- "key": "id"
6997
- }
6998
- ],
6999
6443
  "description": "Calendar ID, or `primary` / `default` for the signed-in user’s default calendar. Returned by `ask-marcel-office list-calendars`."
7000
6444
  },
7001
6445
  {
7002
6446
  "name": "start-date-time",
7003
6447
  "key": "startDateTime",
7004
6448
  "required": true,
7005
- "aliases": [
7006
- {
7007
- "name": "start",
7008
- "key": "start"
7009
- }
7010
- ],
7011
6449
  "description": "Lower bound. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
7012
6450
  },
7013
6451
  {
7014
6452
  "name": "end-date-time",
7015
6453
  "key": "endDateTime",
7016
6454
  "required": true,
7017
- "aliases": [
7018
- {
7019
- "name": "end",
7020
- "key": "end"
7021
- }
7022
- ],
7023
6455
  "description": "Upper bound. ISO 8601 UTC (e.g. `2026-04-01T00:00:00Z` or `2026-04-01`) OR a relative shape: `7d` / `1w` / `2h` / `30m` (past), `+7d` (future), `today` / `yesterday` / `tomorrow` / `now`, `monday`-`sunday` (most recent), `last-<weekday>` / `next-<weekday>`, `start-of-week|month|year`, `end-of-week|month|year`. Relative forms resolve at request time relative to the CLI process clock (UTC)."
7024
6456
  },
7025
6457
  {
@@ -7074,12 +6506,6 @@
7074
6506
  "name": "team-id",
7075
6507
  "key": "teamId",
7076
6508
  "required": true,
7077
- "aliases": [
7078
- {
7079
- "name": "id",
7080
- "key": "id"
7081
- }
7082
- ],
7083
6509
  "description": "Microsoft Teams team ID. Returned by `ask-marcel-office list-joined-teams`."
7084
6510
  },
7085
6511
  {
@@ -7110,12 +6536,6 @@
7110
6536
  "name": "team-id",
7111
6537
  "key": "teamId",
7112
6538
  "required": true,
7113
- "aliases": [
7114
- {
7115
- "name": "id",
7116
- "key": "id"
7117
- }
7118
- ],
7119
6539
  "description": "Microsoft Teams team ID."
7120
6540
  }
7121
6541
  ],
@@ -7135,12 +6555,6 @@
7135
6555
  "name": "chat-id",
7136
6556
  "key": "chatId",
7137
6557
  "required": true,
7138
- "aliases": [
7139
- {
7140
- "name": "id",
7141
- "key": "id"
7142
- }
7143
- ],
7144
6558
  "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`."
7145
6559
  },
7146
6560
  {
@@ -7191,12 +6605,6 @@
7191
6605
  "name": "chat-id",
7192
6606
  "key": "chatId",
7193
6607
  "required": true,
7194
- "aliases": [
7195
- {
7196
- "name": "id",
7197
- "key": "id"
7198
- }
7199
- ],
7200
6608
  "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`."
7201
6609
  }
7202
6610
  ],
@@ -7243,29 +6651,13 @@
7243
6651
  "name": "todo-task-list-id",
7244
6652
  "key": "todoTaskListId",
7245
6653
  "required": true,
7246
- "description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`.",
7247
- "aliases": [
7248
- {
7249
- "name": "task-list-id",
7250
- "key": "taskListId"
7251
- },
7252
- {
7253
- "name": "todo-list-id",
7254
- "key": "todoListId"
7255
- }
7256
- ]
6654
+ "description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
7257
6655
  },
7258
6656
  {
7259
6657
  "name": "todo-task-id",
7260
6658
  "key": "todoTaskId",
7261
6659
  "required": true,
7262
- "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).",
7263
- "aliases": [
7264
- {
7265
- "name": "task-id",
7266
- "key": "taskId"
7267
- }
7268
- ]
6660
+ "description": "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`."
7269
6661
  },
7270
6662
  {
7271
6663
  "name": "top",
@@ -7357,21 +6749,7 @@
7357
6749
  "name": "todo-task-list-id",
7358
6750
  "key": "todoTaskListId",
7359
6751
  "required": true,
7360
- "description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`.",
7361
- "aliases": [
7362
- {
7363
- "name": "id",
7364
- "key": "id"
7365
- },
7366
- {
7367
- "name": "task-list-id",
7368
- "key": "taskListId"
7369
- },
7370
- {
7371
- "name": "todo-list-id",
7372
- "key": "todoListId"
7373
- }
7374
- ]
6752
+ "description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
7375
6753
  },
7376
6754
  {
7377
6755
  "name": "top",
@@ -7426,21 +6804,7 @@
7426
6804
  "name": "todo-task-list-id",
7427
6805
  "key": "todoTaskListId",
7428
6806
  "required": true,
7429
- "description": "Microsoft To Do task list ID. Returned by `list-todo-task-lists`.",
7430
- "aliases": [
7431
- {
7432
- "name": "id",
7433
- "key": "id"
7434
- },
7435
- {
7436
- "name": "task-list-id",
7437
- "key": "taskListId"
7438
- },
7439
- {
7440
- "name": "todo-list-id",
7441
- "key": "todoListId"
7442
- }
7443
- ]
6807
+ "description": "Microsoft To Do task list ID. Returned by `list-todo-task-lists`."
7444
6808
  }
7445
6809
  ],
7446
6810
  "example": "ask-marcel-office list-todo-tasks-delta --todo-task-list-id 'AAMkAD...'",
@@ -7508,12 +6872,6 @@
7508
6872
  "name": "user-id",
7509
6873
  "key": "userId",
7510
6874
  "required": true,
7511
- "aliases": [
7512
- {
7513
- "name": "id",
7514
- "key": "id"
7515
- }
7516
- ],
7517
6875
  "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)."
7518
6876
  },
7519
6877
  {
@@ -7902,12 +7260,6 @@
7902
7260
  "name": "drive-id",
7903
7261
  "key": "driveId",
7904
7262
  "required": true,
7905
- "aliases": [
7906
- {
7907
- "name": "id",
7908
- "key": "id"
7909
- }
7910
- ],
7911
7263
  "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."
7912
7264
  },
7913
7265
  {
@@ -7956,20 +7308,14 @@
7956
7308
  "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.",
7957
7309
  "category": "notes",
7958
7310
  "graphMethod": "GET",
7959
- "graphPathTemplate": "/me/onenote/pages?$filter=contains(title,'{title-substring}')",
7311
+ "graphPathTemplate": "/me/onenote/pages?$filter=contains(title,'{query}')",
7960
7312
  "graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/onenote-list-pages",
7961
7313
  "options": [
7962
7314
  {
7963
- "name": "title-substring",
7964
- "key": "titleSubstring",
7315
+ "name": "query",
7316
+ "key": "query",
7965
7317
  "required": true,
7966
- "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.",
7967
- "aliases": [
7968
- {
7969
- "name": "query",
7970
- "key": "query"
7971
- }
7972
- ]
7318
+ "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."
7973
7319
  },
7974
7320
  {
7975
7321
  "name": "top",
@@ -8002,7 +7348,7 @@
8002
7348
  "description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
8003
7349
  }
8004
7350
  ],
8005
- "example": "ask-marcel-office search-onenote-pages --title-substring 'meeting notes' --top 25",
7351
+ "example": "ask-marcel-office search-onenote-pages --query 'meeting notes' --top 25",
8006
7352
  "responseShape": "collection of Microsoft Graph `onenotePage` resources under `value[]` whose title contains the substring",
8007
7353
  "pagination": true
8008
7354
  },
@@ -8063,23 +7409,17 @@
8063
7409
  },
8064
7410
  {
8065
7411
  "name": "update-mail-draft",
8066
- "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.",
7412
+ "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.",
8067
7413
  "category": "mail",
8068
7414
  "graphMethod": "PATCH",
8069
- "graphPathTemplate": "/me/messages/{message-id} (+ a GET of body,isDraft first when {comment} is used)",
7415
+ "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})",
8070
7416
  "graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/message-update",
8071
7417
  "options": [
8072
7418
  {
8073
7419
  "name": "message-id",
8074
7420
  "key": "messageId",
8075
7421
  "required": true,
8076
- "aliases": [
8077
- {
8078
- "name": "id",
8079
- "key": "id"
8080
- }
8081
- ],
8082
- "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.",
7422
+ "description": "Draft message ID to update. Source from create-mail-draft response or list-mail-folder-messages --mail-folder-id drafts.",
8083
7423
  "argumentHint": {
8084
7424
  "kind": "idOrName"
8085
7425
  }
@@ -8094,7 +7434,7 @@
8094
7434
  "name": "body-content",
8095
7435
  "key": "bodyContent",
8096
7436
  "required": false,
8097
- "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."
7437
+ "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."
8098
7438
  },
8099
7439
  {
8100
7440
  "name": "comment",
@@ -8102,6 +7442,19 @@
8102
7442
  "required": false,
8103
7443
  "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."
8104
7444
  },
7445
+ {
7446
+ "name": "replace-quoted-history",
7447
+ "key": "replaceQuotedHistory",
7448
+ "required": false,
7449
+ "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.",
7450
+ "argumentHint": {
7451
+ "kind": "magicValue",
7452
+ "values": [
7453
+ "true",
7454
+ "false"
7455
+ ]
7456
+ }
7457
+ },
8105
7458
  {
8106
7459
  "name": "body-content-type",
8107
7460
  "key": "bodyContentType",
@@ -8150,7 +7503,7 @@
8150
7503
  ],
8151
7504
  "example": "ask-marcel-office update-mail-draft --message-id \"AAMkAD...\" --subject \"Updated: Q3 Report\" --to-recipients \"alice@example.com,charlie@example.com\"",
8152
7505
  "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`.",
8153
- "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",
7506
+ "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",
8154
7507
  "mutates": true
8155
7508
  }
8156
7509
  ]