ask-marcel-office-cli 2.4.0 → 2.5.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/CHANGELOG.md +153 -0
- package/README.md +5 -5
- package/dist/cli.js +1460 -761
- package/dist/commands.json +300 -23
- package/dist/index.js +566 -210
- package/dist/use-cases/commands/convert-group-post-attachment-to-markdown.d.ts +21 -0
- package/dist/use-cases/commands/convert-group-post-to-markdown.d.ts +20 -0
- package/dist/use-cases/commands/convert-mail-attachment-to-markdown.d.ts +6 -3
- package/dist/use-cases/commands/convert-mail-to-markdown.d.ts +35 -3
- package/dist/use-cases/commands/docx-metadata.d.ts +5 -4
- package/dist/use-cases/commands/get-group-post-attachment.d.ts +13 -0
- package/dist/use-cases/commands/get-group-post.d.ts +4 -0
- package/dist/use-cases/commands/list-group-post-attachments.d.ts +4 -0
- package/dist/use-cases/commands/list-group-thread-posts.d.ts +4 -0
- package/docs/COMMANDS.md +15 -9
- package/docs/USAGE.md +6 -6
- package/package.json +2 -1
package/dist/commands.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "ask-marcel-office-cli",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"version": "2.5.0",
|
|
4
|
+
"generatedAt": "2026-09-06T07:44:37.476Z",
|
|
5
5
|
"commands": [
|
|
6
6
|
{
|
|
7
7
|
"name": "convert-calendar-event-attachment-to-markdown",
|
|
@@ -135,6 +135,126 @@
|
|
|
135
135
|
"example": "ask-marcel-office convert-drive-item-zip-to-markdown --drive-id 'b!1234' --item-id '01ABC'",
|
|
136
136
|
"responseShape": "`{ count, files: [{ path, contentType, size, text }] }` — one entry per file in the archive (sorted by path). Convertible files carry `{ contentType, size, text }` (the markdown); unsupported / failed entries carry `{ path, note }` instead. When the archive has more than 100 entries the response adds `truncated: true` + `totalEntries` and only the first 100 are converted."
|
|
137
137
|
},
|
|
138
|
+
{
|
|
139
|
+
"name": "convert-group-post-attachment-to-markdown",
|
|
140
|
+
"summary": "Convert an attachment on one post of a unified (Microsoft 365) group thread to markdown, the `convert-mail-attachment-to-markdown` sibling for a group inbox. Polymorphic on the attachment’s `@odata.type` and sharing the mail pipeline: fileAttachment decodes the inline bytes and converts them locally (docx, xlsx, csv, odt/ods/odp, pptx as per-slide text, pdf text layer, legacy .xls/.doc, an Outlook `.msg` rendered recursively with its quoted chain stripped unless `--keep-quoted true`, plain text passed through); referenceAttachment resolves via `/shares/{token}/driveItem`; an embedded mail, event or contact is rendered locally. There is no PDF sibling here, so an image, a scanned PDF, a legacy `.ppt` and any other unsupported format return a 415 pointing at `get-group-post-attachment` for the raw bytes.",
|
|
141
|
+
"category": "mail",
|
|
142
|
+
"graphMethod": "GET",
|
|
143
|
+
"graphPathTemplate": "/groups/{group-id}/threads/{thread-id}/posts/{post-id}/attachments/{attachment-id}",
|
|
144
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/attachment-get",
|
|
145
|
+
"options": [
|
|
146
|
+
{
|
|
147
|
+
"name": "group-id",
|
|
148
|
+
"key": "groupId",
|
|
149
|
+
"required": true,
|
|
150
|
+
"description": "Azure AD group object ID for a unified (Microsoft 365) group the signed-in user belongs to."
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "thread-id",
|
|
154
|
+
"key": "threadId",
|
|
155
|
+
"required": true,
|
|
156
|
+
"description": "Conversation thread ID, the `id` of a `list-group-threads` entry."
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"name": "post-id",
|
|
160
|
+
"key": "postId",
|
|
161
|
+
"required": true,
|
|
162
|
+
"description": "Post ID inside that thread. Returned by `list-group-thread-posts`."
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "attachment-id",
|
|
166
|
+
"key": "attachmentId",
|
|
167
|
+
"required": true,
|
|
168
|
+
"description": "Attachment ID inside that post. Returned by `list-group-post-attachments`."
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "include-metadata",
|
|
172
|
+
"key": "includeMetadata",
|
|
173
|
+
"required": false,
|
|
174
|
+
"description": "Pass `--include-metadata true` to append the Office side-channel metadata block, exactly as `convert-mail-attachment-to-markdown` documents it. No-op on other attachment types.",
|
|
175
|
+
"argumentHint": {
|
|
176
|
+
"kind": "magicValue",
|
|
177
|
+
"values": [
|
|
178
|
+
"true",
|
|
179
|
+
"false"
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"name": "keep-quoted",
|
|
185
|
+
"key": "keepQuoted",
|
|
186
|
+
"required": false,
|
|
187
|
+
"description": "Applies to Outlook `.msg` input only. The quoted reply chain / forwarded-message block is stripped by default (it duplicates history and inflates the context budget) and replaced with a single visible marker naming this flag, so nothing is removed silently. Pass `--keep-quoted true` to render the full body. The recognized markers are the same set `convert-mail-to-markdown` uses — see `ask-marcel-office docs convert-mail-to-markdown`.",
|
|
188
|
+
"argumentHint": {
|
|
189
|
+
"kind": "magicValue",
|
|
190
|
+
"values": [
|
|
191
|
+
"true",
|
|
192
|
+
"false"
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"example": "ask-marcel-office convert-group-post-attachment-to-markdown --group-id 'a1b2c3d4-...' --thread-id 'AAQkAD...' --post-id 'AQMkAD...' --attachment-id 'AAMkAD...'",
|
|
198
|
+
"responseShape": "`{ contentType: \"text/markdown\", size, text }` on success (file and reference attachments run through the conversion dispatch; an embedded item is rendered locally). Plain-text sources return the raw-bytes envelope, and a PDF source carries `pageCount`. Unsupported types return an api_error with status 415 naming `get-group-post-attachment` as the way to the bytes.",
|
|
199
|
+
"producesBytes": true
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "convert-group-post-to-markdown",
|
|
203
|
+
"summary": "Render one post of a unified (Microsoft 365) group thread as markdown, the way `convert-mail-to-markdown` renders an Outlook message: a `**From:**` line, a `**Date:**` line, then the HTML body through turndown with quoted reply chains stripped. A post arrives from the group's own address with the writer in `sender`, so the author line reads `Robin Chen <robin.chen@contoso.com> on behalf of Support <support@contoso.com>`. There is no subject line: the thread `topic` is the subject and lives on `list-group-threads`. By default no image bytes are fetched; inline `cid:` images render as `[inline image: <name>]` placeholders unless `--inline-images true`. File attachments are listed below the body by name, size and id and their bytes are never fetched here; read one with `convert-group-post-attachment-to-markdown` or fetch it with `get-group-post-attachment`. Same staged-fetch design as the mail command: one call for the post, one for the attachment list when `hasAttachments` is true or the body references a `cid:` image (Graph reports false for a post whose only attachments are inline), and with `--inline-images true` one per small inline image.",
|
|
204
|
+
"category": "mail",
|
|
205
|
+
"graphMethod": "GET",
|
|
206
|
+
"graphPathTemplate": "/groups/{group-id}/threads/{thread-id}/posts/{post-id}",
|
|
207
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/post-get",
|
|
208
|
+
"options": [
|
|
209
|
+
{
|
|
210
|
+
"name": "group-id",
|
|
211
|
+
"key": "groupId",
|
|
212
|
+
"required": true,
|
|
213
|
+
"description": "Azure AD group object ID for a unified (Microsoft 365) group the signed-in user belongs to."
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"name": "thread-id",
|
|
217
|
+
"key": "threadId",
|
|
218
|
+
"required": true,
|
|
219
|
+
"description": "Conversation thread ID, the `id` of a `list-group-threads` entry."
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"name": "post-id",
|
|
223
|
+
"key": "postId",
|
|
224
|
+
"required": true,
|
|
225
|
+
"description": "Post ID inside that thread. Returned by `list-group-thread-posts`."
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"name": "inline-images",
|
|
229
|
+
"key": "inlineImages",
|
|
230
|
+
"required": false,
|
|
231
|
+
"description": "Pass `--inline-images true` to fetch small inline images (≤ 2 MB, `image/*` only) and embed them as base64 `data:` URIs. Default is `false`: no per-image bytes fetch, and every inline `cid:` image renders as a `[inline image: <name>]` placeholder while still appearing in the attachments list. Same rule as `convert-mail-to-markdown`.",
|
|
232
|
+
"argumentHint": {
|
|
233
|
+
"kind": "magicValue",
|
|
234
|
+
"values": [
|
|
235
|
+
"true",
|
|
236
|
+
"false"
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"name": "keep-quoted",
|
|
242
|
+
"key": "keepQuoted",
|
|
243
|
+
"required": false,
|
|
244
|
+
"description": "Quoted reply chains and forwarded-message blocks are stripped by default and replaced with a single visible marker naming this flag; the `note` reports the share of the body text that went with them. Pass `--keep-quoted true` to preserve the full body. The markers recognised are the ones `convert-mail-to-markdown` documents.",
|
|
245
|
+
"argumentHint": {
|
|
246
|
+
"kind": "magicValue",
|
|
247
|
+
"values": [
|
|
248
|
+
"true",
|
|
249
|
+
"false"
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
],
|
|
254
|
+
"example": "ask-marcel-office convert-group-post-to-markdown --group-id 'a1b2c3d4-...' --thread-id 'AAQkAD...' --post-id 'AQMkAD...'",
|
|
255
|
+
"responseShape": "`{ contentType: \"text/markdown\", size, text, note? }`, the same envelope as `convert-mail-to-markdown`: headers, the turndown-rendered body and, when present, an attachments list. The optional `note` carries the attachments-list failure hint and/or the quoted-chain notice with the share of the body text it removed.",
|
|
256
|
+
"producesBytes": true
|
|
257
|
+
},
|
|
138
258
|
{
|
|
139
259
|
"name": "convert-local-file-to-markdown",
|
|
140
260
|
"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.",
|
|
@@ -340,7 +460,7 @@
|
|
|
340
460
|
},
|
|
341
461
|
{
|
|
342
462
|
"name": "convert-mail-to-markdown",
|
|
343
|
-
"summary": "Render a single Outlook email as markdown — headers (`**Subject:**`, `**From:**`, `**To:**`, `**Cc:**` only when present, `**Date:**`), followed by the body run through turndown. By default NO image bytes are fetched: every inline `cid:` image renders as a readable `[inline image: <name>]` placeholder and the images surface in the file-attachments list, so the output stays close to the text size (an email whose 6 KB body carried 30 KB of signature-image base64 now ships at ~6 KB). Pass `--inline-images true` to embed inline images (`isInline:true` + `image/*` content-type, size ≤ 2 MB) as base64 `data:` URIs for self-contained output (non-image inline attachments are never embedded; oversize inline images keep a placeholder note; a cid whose per-image fetch fails degrades to the placeholder too). File attachments are always listed below the body by name + size + id; their bytes are NOT fetched here — call `convert-mail-attachment-to-pdf` or `get-mail-attachment` with the id when you actually need them. Staged-fetch design: one call for the body, one for the attachments-metadata list (
|
|
463
|
+
"summary": "Render a single Outlook email as markdown — headers (`**Subject:**`, `**From:**`, `**To:**`, `**Cc:**` only when present, `**Date:**`), followed by the body run through turndown. By default NO image bytes are fetched: every inline `cid:` image renders as a readable `[inline image: <name>]` placeholder and the images surface in the file-attachments list, so the output stays close to the text size (an email whose 6 KB body carried 30 KB of signature-image base64 now ships at ~6 KB). Pass `--inline-images true` to embed inline images (`isInline:true` + `image/*` content-type, size ≤ 2 MB) as base64 `data:` URIs for self-contained output (non-image inline attachments are never embedded; oversize inline images keep a placeholder note; a cid whose per-image fetch fails degrades to the placeholder too). File attachments are always listed below the body by name + size + id; their bytes are NOT fetched here — call `convert-mail-attachment-to-pdf` or `get-mail-attachment` with the id when you actually need them. Staged-fetch design: one call for the body, one for the attachments-metadata list (when `hasAttachments` is true or the body references a `cid:` image, since Graph reports false for inline-only mail), and with `--inline-images true` one per small inline image — replaces the old `?$expand=attachments` which timed out / truncated on messages with multi-MB attachments.",
|
|
344
464
|
"category": "mail",
|
|
345
465
|
"graphMethod": "GET",
|
|
346
466
|
"graphPathTemplate": "/me/messages/{message-id}",
|
|
@@ -607,7 +727,7 @@
|
|
|
607
727
|
"name": "include-metadata",
|
|
608
728
|
"key": "includeMetadata",
|
|
609
729
|
"required": false,
|
|
610
|
-
"description": "Pass `--include-metadata true` to surface the side-channel content the rendered body hides. For docx (`## DOCX metadata`): core/app/custom document properties, people registry, external hyperlinks, comments, tracked changes (a deletion sitting next to an insertion by the same author is reported once as a `replacement` carrying `before` + `after`; the halves that pair with nothing stay under `insertions` / `deletions`; `moves` joins the two ends of a moved span by its range name; `formatChanges` names which run or
|
|
730
|
+
"description": "Pass `--include-metadata true` to surface the side-channel content the rendered body hides. For docx (`## DOCX metadata`): core/app/custom document properties, people registry, external hyperlinks, comments, tracked changes (a deletion sitting next to an insertion by the same author is reported once as a `replacement` carrying `before` + `after`; the halves that pair with nothing stay under `insertions` / `deletions`; `moves` joins the two ends of a moved span by its range name; `formatChanges` names which run, paragraph, table, row or cell properties a reviewer altered, and a property whose values hang off child elements rather than its own attributes (`w:tblBorders` is the common one) is reported with its author and scope but names no property. Structural revisions — cell insert / delete / merge, numbering and section properties — are still unreported), hidden-formatted text (w:vanish), field instructions (MERGEFIELD / HYPERLINK / DOCVARIABLE), bookmarks. For xlsx (`## Workbook metadata`): core/app/custom properties, external relationships, defined names, hidden / very-hidden sheets, legacy cell comments, threaded comments, persons. For pptx (`## PPTX metadata`): properties, external relationships, slide tags, comment authors + comments (legacy + modern), and per-slide title / speaker notes / hidden flag — returned as a standalone document since pptx has no convertible body (use `download-drive-item-as-pdf` for slide visuals). For OpenDocument (`.odt`/`.ods`/`.odp`, `## OpenDocument metadata`): Dublin Core + ODF properties, keywords, user-defined custom fields — appended after the converted body. Each OOXML family also covers its macro-enabled (`.docm` / `.xlsm` / `.pptm`) and template (`.dotx` / `.xltx` / `.potx`, etc.) variants, with a `### Macros (VBA)` section flagging an embedded `vbaProject.bin`. No-op on other sources.",
|
|
611
731
|
"argumentHint": {
|
|
612
732
|
"kind": "magicValue",
|
|
613
733
|
"values": [
|
|
@@ -1572,6 +1692,97 @@
|
|
|
1572
1692
|
"example": "ask-marcel-office get-group --group-id 'a1b2c3d4-...' --select 'id,displayName,mail'",
|
|
1573
1693
|
"responseShape": "single Microsoft Graph `group` resource"
|
|
1574
1694
|
},
|
|
1695
|
+
{
|
|
1696
|
+
"name": "get-group-post",
|
|
1697
|
+
"summary": "Get a single post of a unified (Microsoft 365) group thread by ID, the sibling of `get-mail-message` for a group inbox: the full `post` resource including the HTML `body`. `--select` trims the projection. `--expand attachments` returns every attachment inline with its base64 `contentBytes`, which is convenient for a small post and the wrong shape for one carrying a multi-MB file: list them with `list-group-post-attachments` and fetch one with `get-group-post-attachment` instead. Post IDs come from `list-group-thread-posts`; use `convert-group-post-to-markdown` for a readable rendering.",
|
|
1698
|
+
"category": "mail",
|
|
1699
|
+
"graphMethod": "GET",
|
|
1700
|
+
"graphPathTemplate": "/groups/{group-id}/threads/{thread-id}/posts/{post-id}",
|
|
1701
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/post-get",
|
|
1702
|
+
"options": [
|
|
1703
|
+
{
|
|
1704
|
+
"name": "group-id",
|
|
1705
|
+
"key": "groupId",
|
|
1706
|
+
"required": true,
|
|
1707
|
+
"description": "Azure AD group object ID for a unified (Microsoft 365) group the signed-in user belongs to."
|
|
1708
|
+
},
|
|
1709
|
+
{
|
|
1710
|
+
"name": "thread-id",
|
|
1711
|
+
"key": "threadId",
|
|
1712
|
+
"required": true,
|
|
1713
|
+
"description": "Conversation thread ID, the `id` of a `list-group-threads` entry."
|
|
1714
|
+
},
|
|
1715
|
+
{
|
|
1716
|
+
"name": "post-id",
|
|
1717
|
+
"key": "postId",
|
|
1718
|
+
"required": true,
|
|
1719
|
+
"description": "Post ID inside that thread. Returned by `list-group-thread-posts`."
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
"name": "select",
|
|
1723
|
+
"key": "select",
|
|
1724
|
+
"required": false,
|
|
1725
|
+
"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`."
|
|
1726
|
+
},
|
|
1727
|
+
{
|
|
1728
|
+
"name": "expand",
|
|
1729
|
+
"key": "expand",
|
|
1730
|
+
"required": false,
|
|
1731
|
+
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
1732
|
+
}
|
|
1733
|
+
],
|
|
1734
|
+
"example": "ask-marcel-office get-group-post --group-id 'a1b2c3d4-...' --thread-id 'AAQkAD...' --post-id 'AQMkAD...'",
|
|
1735
|
+
"responseShape": "single Microsoft Graph `post` resource: `id`, `createdDateTime`, `lastModifiedDateTime`, `changeKey`, `categories`, `receivedDateTime`, `hasAttachments`, `body { contentType, content }`, `from` (normally the group address), `sender` (the person who wrote it). With `--expand attachments`, an `attachments[]` array of `fileAttachment` / `itemAttachment` / `referenceAttachment` entries, file attachments carrying `contentBytes` inline."
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
"name": "get-group-post-attachment",
|
|
1739
|
+
"summary": "Get a single attachment on one post of a unified (Microsoft 365) group thread, the `get-mail-attachment` sibling for a group inbox. Prefer it over `get-group-post --expand attachments`, which expands every attachment at once. fileAttachments carry a `base64` mirror of `contentBytes` so the global output-path flag lands the bytes on disk in one call; with an output-path set both byte fields are stripped from stdout in favour of `savedTo`. Pass `--select id,name,contentType,size` for metadata only. This is also the route to an image attached to a post: fetch the bytes and feed them to a vision-capable model.",
|
|
1740
|
+
"category": "mail",
|
|
1741
|
+
"graphMethod": "GET",
|
|
1742
|
+
"graphPathTemplate": "/groups/{group-id}/threads/{thread-id}/posts/{post-id}/attachments/{attachment-id}",
|
|
1743
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/attachment-get",
|
|
1744
|
+
"options": [
|
|
1745
|
+
{
|
|
1746
|
+
"name": "group-id",
|
|
1747
|
+
"key": "groupId",
|
|
1748
|
+
"required": true,
|
|
1749
|
+
"description": "Azure AD group object ID for a unified (Microsoft 365) group the signed-in user belongs to."
|
|
1750
|
+
},
|
|
1751
|
+
{
|
|
1752
|
+
"name": "thread-id",
|
|
1753
|
+
"key": "threadId",
|
|
1754
|
+
"required": true,
|
|
1755
|
+
"description": "Conversation thread ID, the `id` of a `list-group-threads` entry."
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
"name": "post-id",
|
|
1759
|
+
"key": "postId",
|
|
1760
|
+
"required": true,
|
|
1761
|
+
"description": "Post ID inside that thread. Returned by `list-group-thread-posts`."
|
|
1762
|
+
},
|
|
1763
|
+
{
|
|
1764
|
+
"name": "attachment-id",
|
|
1765
|
+
"key": "attachmentId",
|
|
1766
|
+
"required": true,
|
|
1767
|
+
"description": "Attachment ID inside that post. Returned by `list-group-post-attachments`."
|
|
1768
|
+
},
|
|
1769
|
+
{
|
|
1770
|
+
"name": "select",
|
|
1771
|
+
"key": "select",
|
|
1772
|
+
"required": false,
|
|
1773
|
+
"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`."
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
"name": "expand",
|
|
1777
|
+
"key": "expand",
|
|
1778
|
+
"required": false,
|
|
1779
|
+
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
1780
|
+
}
|
|
1781
|
+
],
|
|
1782
|
+
"example": "ask-marcel-office get-group-post-attachment --group-id 'a1b2c3d4-...' --thread-id 'AAQkAD...' --post-id 'AQMkAD...' --attachment-id 'AAMkAD...'",
|
|
1783
|
+
"responseShape": "single Microsoft Graph `attachment` resource. fileAttachments include `contentBytes` (Graph) AND `base64` (CLI mirror) so `--output-path` works; with `--output-path` set, both byte fields are stripped from stdout and replaced by `savedTo`. itemAttachments and referenceAttachments are returned unchanged.",
|
|
1784
|
+
"producesBytes": true
|
|
1785
|
+
},
|
|
1575
1786
|
{
|
|
1576
1787
|
"name": "get-mail-attachment",
|
|
1577
1788
|
"summary": "Get a single attachment on an Outlook message (metadata, plus the base64 `contentBytes` for file attachments). For fileAttachments, the response also carries a `base64` mirror of `contentBytes` so the global output-path flag can land the bytes on disk in one call — and when an output-path is set the CLI strips BOTH `contentBytes` and `base64` from stdout, leaving a compact metadata envelope with `savedTo` (the file is on disk; no multi-MB base64 in the terminal). When you only want metadata, use `--select id,name,contentType,size` to skip the `contentBytes` payload.",
|
|
@@ -1974,7 +2185,7 @@
|
|
|
1974
2185
|
},
|
|
1975
2186
|
{
|
|
1976
2187
|
"name": "get-shared-mailbox-message",
|
|
1977
|
-
"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.",
|
|
2188
|
+
"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. Requires the delegated `Mail.Read.Shared` scope, which neither token this CLI can mint carries (verified live on two tenants, 2026-08-30), so any mailbox other than the signed-in user's own is expected to answer `ErrorAccessDenied` whatever delegation Exchange holds. Your own UPN works; a Microsoft 365 group's mailbox is the shared-mail path that does (`list-group-conversations`, `list-group-thread-posts`).",
|
|
1978
2189
|
"category": "mail",
|
|
1979
2190
|
"graphMethod": "GET",
|
|
1980
2191
|
"graphPathTemplate": "/users/{user-id}/messages/{message-id}",
|
|
@@ -4032,7 +4243,7 @@
|
|
|
4032
4243
|
},
|
|
4033
4244
|
{
|
|
4034
4245
|
"name": "list-group-conversations",
|
|
4035
|
-
"summary": "List conversations in a unified (Microsoft 365) group inbox. Each conversation aggregates one or more threads. Only Microsoft 365 groups have a mailbox — security and distribution groups return `MailboxNotEnabledForRESTAPI`. Verify the group is unified before calling.",
|
|
4246
|
+
"summary": "List conversations in a unified (Microsoft 365) group inbox. Each conversation aggregates one or more threads. Only Microsoft 365 groups have a mailbox — security and distribution groups return `MailboxNotEnabledForRESTAPI`. Verify the group is unified before calling. Bodies live two levels down: `list-group-threads` then `list-group-thread-posts`, or `--expand 'threads($expand=posts)'` here to fetch conversations, threads and posts in one call.",
|
|
4036
4247
|
"category": "mail",
|
|
4037
4248
|
"graphMethod": "GET",
|
|
4038
4249
|
"graphPathTemplate": "/groups/{group-id}/conversations",
|
|
@@ -4062,12 +4273,6 @@
|
|
|
4062
4273
|
"required": false,
|
|
4063
4274
|
"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`."
|
|
4064
4275
|
},
|
|
4065
|
-
{
|
|
4066
|
-
"name": "filter",
|
|
4067
|
-
"key": "filter",
|
|
4068
|
-
"required": false,
|
|
4069
|
-
"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."
|
|
4070
|
-
},
|
|
4071
4276
|
{
|
|
4072
4277
|
"name": "orderby",
|
|
4073
4278
|
"key": "orderby",
|
|
@@ -4250,9 +4455,87 @@
|
|
|
4250
4455
|
"responseShape": "collection of Microsoft Graph `directoryObject` resources under `value[]`",
|
|
4251
4456
|
"pagination": true
|
|
4252
4457
|
},
|
|
4458
|
+
{
|
|
4459
|
+
"name": "list-group-post-attachments",
|
|
4460
|
+
"summary": "List the attachments (file, item, reference) on one post of a unified (Microsoft 365) group thread. Ships the slim default `--select=id,name,contentType,size,isInline` the mail and calendar siblings use, so a caller sees what is attached without pulling any bytes — the staged alternative to `get-group-post --expand attachments`, which inlines EVERY attachment at once and times out on a post carrying a multi-MB file. Graph returns the whole collection in one response and silently ignores `$top`, `$skip`, `$orderby` and `$filter` (probed live 2026-09-03), so only `--select` and `--expand` are exposed. A post whose only attachments are inline images reports `hasAttachments: false`, so call this whenever the body shows `cid:` references. Read one with `convert-group-post-attachment-to-markdown`, or fetch its bytes with `get-group-post-attachment`.",
|
|
4461
|
+
"category": "mail",
|
|
4462
|
+
"graphMethod": "GET",
|
|
4463
|
+
"graphPathTemplate": "/groups/{group-id}/threads/{thread-id}/posts/{post-id}/attachments",
|
|
4464
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/post-list-attachments",
|
|
4465
|
+
"options": [
|
|
4466
|
+
{
|
|
4467
|
+
"name": "group-id",
|
|
4468
|
+
"key": "groupId",
|
|
4469
|
+
"required": true,
|
|
4470
|
+
"description": "Azure AD group object ID for a unified (Microsoft 365) group you belong to."
|
|
4471
|
+
},
|
|
4472
|
+
{
|
|
4473
|
+
"name": "thread-id",
|
|
4474
|
+
"key": "threadId",
|
|
4475
|
+
"required": true,
|
|
4476
|
+
"description": "Conversation thread ID, the `id` of a `list-group-threads` entry."
|
|
4477
|
+
},
|
|
4478
|
+
{
|
|
4479
|
+
"name": "post-id",
|
|
4480
|
+
"key": "postId",
|
|
4481
|
+
"required": true,
|
|
4482
|
+
"description": "Post ID inside that thread. Returned by `list-group-thread-posts`."
|
|
4483
|
+
},
|
|
4484
|
+
{
|
|
4485
|
+
"name": "select",
|
|
4486
|
+
"key": "select",
|
|
4487
|
+
"required": false,
|
|
4488
|
+
"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`."
|
|
4489
|
+
},
|
|
4490
|
+
{
|
|
4491
|
+
"name": "expand",
|
|
4492
|
+
"key": "expand",
|
|
4493
|
+
"required": false,
|
|
4494
|
+
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
4495
|
+
}
|
|
4496
|
+
],
|
|
4497
|
+
"example": "ask-marcel-office list-group-post-attachments --group-id 'a1b2c3d4-...' --thread-id 'AAQkAD...' --post-id 'AQMkAD...'",
|
|
4498
|
+
"responseShape": "collection of Microsoft Graph `attachment` resources under `value[]` (slim metadata by default — see summary), with no page cursor. Graph always includes `@odata.type` and `@odata.mediaContentType` on every entry regardless of `--select`; that discriminator is what the converting sibling branches on. An inline image carries `isInline: true` and a `contentId` matching a `cid:` reference in the post body."
|
|
4499
|
+
},
|
|
4500
|
+
{
|
|
4501
|
+
"name": "list-group-thread-posts",
|
|
4502
|
+
"summary": "List every post in one thread of a unified (Microsoft 365) group inbox: the full `post` resources with the HTML `body.content`, `from`, `sender`, `receivedDateTime` and `hasAttachments`, where `list-group-threads` stops at a truncated `preview`. Graph returns the whole thread in one call with no page cursor, and it silently ignores `$top`, `$skip` and `$orderby` while rejecting `$filter` (probed live 2026-09-03), so only `--select` and `--expand` are exposed; sort on `receivedDateTime` client-side if order matters. `sender` is the person who wrote the post and `from` is normally the group's own address. Render one post as markdown with `convert-group-post-to-markdown`. Access is membership-gated, not scope-gated: a group the signed-in user does not belong to answers `ErrorAccessDenied` even though `list-groups` lists it.",
|
|
4503
|
+
"category": "mail",
|
|
4504
|
+
"graphMethod": "GET",
|
|
4505
|
+
"graphPathTemplate": "/groups/{group-id}/threads/{thread-id}/posts",
|
|
4506
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/conversationthread-list-posts",
|
|
4507
|
+
"options": [
|
|
4508
|
+
{
|
|
4509
|
+
"name": "group-id",
|
|
4510
|
+
"key": "groupId",
|
|
4511
|
+
"required": true,
|
|
4512
|
+
"description": "Azure AD group object ID for a unified (Microsoft 365) group the signed-in user belongs to."
|
|
4513
|
+
},
|
|
4514
|
+
{
|
|
4515
|
+
"name": "thread-id",
|
|
4516
|
+
"key": "threadId",
|
|
4517
|
+
"required": true,
|
|
4518
|
+
"description": "Conversation thread ID, the `id` of a `list-group-threads` entry (also inlined by `list-group-conversations --expand threads`)."
|
|
4519
|
+
},
|
|
4520
|
+
{
|
|
4521
|
+
"name": "select",
|
|
4522
|
+
"key": "select",
|
|
4523
|
+
"required": false,
|
|
4524
|
+
"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`."
|
|
4525
|
+
},
|
|
4526
|
+
{
|
|
4527
|
+
"name": "expand",
|
|
4528
|
+
"key": "expand",
|
|
4529
|
+
"required": false,
|
|
4530
|
+
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
4531
|
+
}
|
|
4532
|
+
],
|
|
4533
|
+
"example": "ask-marcel-office list-group-thread-posts --group-id 'a1b2c3d4-...' --thread-id 'AAQkAD...'",
|
|
4534
|
+
"responseShape": "collection of Microsoft Graph `post` resources under `value[]`: `id`, `createdDateTime`, `lastModifiedDateTime`, `changeKey`, `categories`, `receivedDateTime`, `hasAttachments`, `body { contentType, content }`, `from`, `sender`. No `nextLink` is ever emitted. `hasAttachments` is false for a post whose only attachments are inline images. `--expand attachments` inlines every attachment of every post with its base64 `contentBytes`, so use it sparingly."
|
|
4535
|
+
},
|
|
4253
4536
|
{
|
|
4254
4537
|
"name": "list-group-threads",
|
|
4255
|
-
"summary": "List threads in a unified (Microsoft 365) group inbox. Threads are flatter than conversations — one per topic, useful when conversation-level grouping isn't needed. Only Microsoft 365 groups have a mailbox — security and distribution groups return `MailboxNotEnabledForRESTAPI`.",
|
|
4538
|
+
"summary": "List threads in a unified (Microsoft 365) group inbox. Threads are flatter than conversations — one per topic, useful when conversation-level grouping isn't needed. Only Microsoft 365 groups have a mailbox — security and distribution groups return `MailboxNotEnabledForRESTAPI`. Each thread carries only a truncated `preview` of its latest post: read the full posts with `list-group-thread-posts`, or pass `--expand posts` here to inline them.",
|
|
4256
4539
|
"category": "mail",
|
|
4257
4540
|
"graphMethod": "GET",
|
|
4258
4541
|
"graphPathTemplate": "/groups/{group-id}/threads",
|
|
@@ -4282,12 +4565,6 @@
|
|
|
4282
4565
|
"required": false,
|
|
4283
4566
|
"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`."
|
|
4284
4567
|
},
|
|
4285
|
-
{
|
|
4286
|
-
"name": "filter",
|
|
4287
|
-
"key": "filter",
|
|
4288
|
-
"required": false,
|
|
4289
|
-
"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."
|
|
4290
|
-
},
|
|
4291
4568
|
{
|
|
4292
4569
|
"name": "orderby",
|
|
4293
4570
|
"key": "orderby",
|
|
@@ -5716,7 +5993,7 @@
|
|
|
5716
5993
|
},
|
|
5717
5994
|
{
|
|
5718
5995
|
"name": "list-shared-mailbox-child-folders",
|
|
5719
|
-
"summary": "List the subfolders of one mail folder in a shared or delegated mailbox. The `/me` sibling is `list-mail-child-folders`. Walk it from the folder IDs `list-shared-mailbox-folders` returns to reach nested custom folders.
|
|
5996
|
+
"summary": "List the subfolders of one mail folder in a shared or delegated mailbox. The `/me` sibling is `list-mail-child-folders`. Walk it from the folder IDs `list-shared-mailbox-folders` returns to reach nested custom folders. Requires the delegated `Mail.Read.Shared` scope, which neither token this CLI can mint carries (verified live on two tenants, 2026-08-30), so any mailbox other than the signed-in user's own is expected to answer `ErrorAccessDenied` whatever delegation Exchange holds. Your own UPN works; a Microsoft 365 group's mailbox is the shared-mail path that does (`list-group-conversations`, `list-group-thread-posts`).",
|
|
5720
5997
|
"category": "mail",
|
|
5721
5998
|
"graphMethod": "GET",
|
|
5722
5999
|
"graphPathTemplate": "/users/{user-id}/mailFolders/{mail-folder-id}/childFolders",
|
|
@@ -5790,7 +6067,7 @@
|
|
|
5790
6067
|
},
|
|
5791
6068
|
{
|
|
5792
6069
|
"name": "list-shared-mailbox-folder-messages",
|
|
5793
|
-
"summary": "List messages in a single folder of a shared / delegated mailbox.",
|
|
6070
|
+
"summary": "List messages in a single folder of a shared / delegated mailbox. Requires the delegated `Mail.Read.Shared` scope, which neither token this CLI can mint carries (verified live on two tenants, 2026-08-30), so any mailbox other than the signed-in user's own is expected to answer `ErrorAccessDenied` whatever delegation Exchange holds. Your own UPN works; a Microsoft 365 group's mailbox is the shared-mail path that does (`list-group-conversations`, `list-group-thread-posts`).",
|
|
5794
6071
|
"category": "mail",
|
|
5795
6072
|
"graphMethod": "GET",
|
|
5796
6073
|
"graphPathTemplate": "/users/{user-id}/mailFolders/{mail-folder-id}/messages",
|
|
@@ -5851,7 +6128,7 @@
|
|
|
5851
6128
|
},
|
|
5852
6129
|
{
|
|
5853
6130
|
"name": "list-shared-mailbox-folders",
|
|
5854
|
-
"summary": "List the top-level mail folders of a shared or delegated mailbox. The `/me` sibling is `list-mail-folders`. Use it to discover the folder IDs that `list-shared-mailbox-folder-messages` needs: without it only the well-known names (`inbox`, `sentitems`, `drafts`, …) are reachable, so custom folders are invisible.
|
|
6131
|
+
"summary": "List the top-level mail folders of a shared or delegated mailbox. The `/me` sibling is `list-mail-folders`. Use it to discover the folder IDs that `list-shared-mailbox-folder-messages` needs: without it only the well-known names (`inbox`, `sentitems`, `drafts`, …) are reachable, so custom folders are invisible. Requires the delegated `Mail.Read.Shared` scope, which neither token this CLI can mint carries (verified live on two tenants, 2026-08-30), so any mailbox other than the signed-in user's own is expected to answer `ErrorAccessDenied` whatever delegation Exchange holds. Your own UPN works; a Microsoft 365 group's mailbox is the shared-mail path that does (`list-group-conversations`, `list-group-thread-posts`).",
|
|
5855
6132
|
"category": "mail",
|
|
5856
6133
|
"graphMethod": "GET",
|
|
5857
6134
|
"graphPathTemplate": "/users/{user-id}/mailFolders",
|
|
@@ -5919,7 +6196,7 @@
|
|
|
5919
6196
|
},
|
|
5920
6197
|
{
|
|
5921
6198
|
"name": "list-shared-mailbox-messages",
|
|
5922
|
-
"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.
|
|
6199
|
+
"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. Requires the delegated `Mail.Read.Shared` scope, which neither token this CLI can mint carries (verified live on two tenants, 2026-08-30), so any mailbox other than the signed-in user's own is expected to answer `ErrorAccessDenied` whatever delegation Exchange holds. Your own UPN works; a Microsoft 365 group's mailbox is the shared-mail path that does (`list-group-conversations`, `list-group-thread-posts`).",
|
|
5923
6200
|
"category": "mail",
|
|
5924
6201
|
"graphMethod": "GET",
|
|
5925
6202
|
"graphPathTemplate": "/users/{user-id}/messages",
|