ask-marcel-office-cli 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +283 -0
- package/README.md +178 -119
- package/dist/cli.js +44725 -27155
- package/dist/commands.json +406 -734
- package/dist/composition/build-deps.d.ts +8 -0
- package/dist/composition/mcp.d.ts +20 -0
- package/dist/composition/run-registry-command.d.ts +43 -0
- package/dist/domain/tenant-id.d.ts +9 -0
- package/dist/domain/utilities/spo-tenant.d.ts +20 -0
- package/dist/index.js +2831 -1833
- package/dist/infra/auth.d.ts +36 -14
- package/dist/infra/browser-auth.d.ts +7 -2
- package/dist/infra/graph-client.d.ts +52 -16
- package/dist/presenter/graph-cursor.d.ts +2 -0
- package/dist/presenter/output.d.ts +2 -2
- package/dist/presenter/render-to-string.d.ts +47 -0
- package/dist/use-cases/commands/build-command.d.ts +19 -2
- package/dist/use-cases/commands/command-types.d.ts +17 -31
- package/dist/use-cases/commands/convert-calendar-event-attachment-to-markdown.d.ts +4 -0
- package/dist/use-cases/commands/{convert-drive-item-zip.d.ts → convert-drive-item-zip-to-markdown.d.ts} +5 -0
- package/dist/use-cases/commands/{convert-local-file.d.ts → convert-local-file-to-markdown.d.ts} +4 -0
- package/dist/use-cases/commands/convert-mail-attachment-to-markdown.d.ts +10 -2
- package/dist/use-cases/commands/{convert-mail-attachment-zip.d.ts → convert-mail-attachment-zip-to-markdown.d.ts} +5 -1
- package/dist/use-cases/commands/convert-mail-to-markdown.d.ts +35 -1
- package/dist/use-cases/commands/create-forward-draft.d.ts +5 -1
- package/dist/use-cases/commands/create-reply-draft.d.ts +9 -1
- package/dist/use-cases/commands/docs-render.d.ts +0 -1
- package/dist/use-cases/commands/download-drive-item-as-markdown.d.ts +7 -2
- package/dist/use-cases/commands/download-drive-item-as-pdf.d.ts +1 -0
- package/dist/use-cases/commands/download-drive-item-content.d.ts +1 -0
- package/dist/use-cases/commands/draft-comment-splicer.d.ts +36 -0
- package/dist/use-cases/commands/draft-dedup.d.ts +18 -0
- package/dist/use-cases/commands/draft-response.d.ts +4 -0
- package/dist/use-cases/commands/extract-drive-item-images.d.ts +1 -0
- package/dist/use-cases/commands/extract-local-file-images.d.ts +1 -1
- package/dist/use-cases/commands/fetch-raw-bytes.d.ts +13 -0
- package/dist/use-cases/commands/find-mail-drafts.d.ts +9 -0
- package/dist/use-cases/commands/get-mail-signature.d.ts +8 -0
- package/dist/use-cases/commands/get-user.d.ts +10 -0
- package/dist/use-cases/commands/inline-image-embedder.d.ts +2 -1
- package/dist/use-cases/commands/list-mail-folder-messages-delta.d.ts +10 -2
- package/dist/use-cases/commands/login-status.d.ts +9 -27
- package/dist/use-cases/commands/login.d.ts +21 -0
- package/dist/use-cases/commands/mail-message-select.d.ts +1 -0
- package/dist/use-cases/commands/mail-quote-stripper.d.ts +16 -15
- package/dist/use-cases/commands/markdown-dispatch.d.ts +2 -1
- package/dist/use-cases/commands/msg-to-markdown.d.ts +10 -1
- package/dist/use-cases/commands/odata-query.d.ts +15 -1
- package/dist/use-cases/commands/office-to-markdown.d.ts +1 -0
- package/dist/use-cases/commands/read-mail-attachment.d.ts +4 -0
- package/dist/use-cases/commands/reject-unknown-params.d.ts +16 -0
- package/dist/use-cases/commands/resolve-command.d.ts +23 -0
- package/dist/use-cases/commands/search-all-files.d.ts +8 -0
- package/dist/use-cases/commands/search-escape.d.ts +23 -0
- package/dist/use-cases/commands/search-onenote-pages.d.ts +1 -1
- package/dist/use-cases/commands/signature-extractor.d.ts +2 -0
- package/dist/use-cases/commands/tenant-option.d.ts +44 -0
- package/dist/use-cases/commands/update-mail-draft.d.ts +5 -0
- package/dist/use-cases/commands/zip-archive-to-markdown.d.ts +10 -5
- package/dist/use-cases/ports/filesystem.d.ts +1 -1
- package/docs/COMMANDS.md +38 -33
- package/docs/USAGE.md +65 -7
- 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-07-
|
|
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",
|
|
@@ -35,6 +35,19 @@
|
|
|
35
35
|
"false"
|
|
36
36
|
]
|
|
37
37
|
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "keep-quoted",
|
|
41
|
+
"key": "keepQuoted",
|
|
42
|
+
"required": false,
|
|
43
|
+
"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`.",
|
|
44
|
+
"argumentHint": {
|
|
45
|
+
"kind": "magicValue",
|
|
46
|
+
"values": [
|
|
47
|
+
"true",
|
|
48
|
+
"false"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
38
51
|
}
|
|
39
52
|
],
|
|
40
53
|
"example": "ask-marcel-office convert-calendar-event-attachment-to-markdown --event-id 'AAMkAD...' --attachment-id 'AAMkAD...attach1'",
|
|
@@ -67,7 +80,7 @@
|
|
|
67
80
|
"producesBytes": true
|
|
68
81
|
},
|
|
69
82
|
{
|
|
70
|
-
"name": "convert-drive-item-zip",
|
|
83
|
+
"name": "convert-drive-item-zip-to-markdown",
|
|
71
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`.",
|
|
72
85
|
"category": "drive",
|
|
73
86
|
"graphMethod": "GET",
|
|
@@ -86,6 +99,12 @@
|
|
|
86
99
|
"required": true,
|
|
87
100
|
"description": "driveItem ID of the .zip file. Returned by `list-folder-files` or `search-onedrive-files`."
|
|
88
101
|
},
|
|
102
|
+
{
|
|
103
|
+
"name": "tenant-id",
|
|
104
|
+
"key": "tenantId",
|
|
105
|
+
"required": false,
|
|
106
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
107
|
+
},
|
|
89
108
|
{
|
|
90
109
|
"name": "include-metadata",
|
|
91
110
|
"key": "includeMetadata",
|
|
@@ -98,14 +117,27 @@
|
|
|
98
117
|
"false"
|
|
99
118
|
]
|
|
100
119
|
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "keep-quoted",
|
|
123
|
+
"key": "keepQuoted",
|
|
124
|
+
"required": false,
|
|
125
|
+
"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`.",
|
|
126
|
+
"argumentHint": {
|
|
127
|
+
"kind": "magicValue",
|
|
128
|
+
"values": [
|
|
129
|
+
"true",
|
|
130
|
+
"false"
|
|
131
|
+
]
|
|
132
|
+
}
|
|
101
133
|
}
|
|
102
134
|
],
|
|
103
|
-
"example": "ask-marcel-office convert-drive-item-zip --drive-id 'b!1234' --item-id '01ABC'",
|
|
135
|
+
"example": "ask-marcel-office convert-drive-item-zip-to-markdown --drive-id 'b!1234' --item-id '01ABC'",
|
|
104
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."
|
|
105
137
|
},
|
|
106
138
|
{
|
|
107
|
-
"name": "convert-local-file",
|
|
108
|
-
"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, 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.",
|
|
139
|
+
"name": "convert-local-file-to-markdown",
|
|
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.",
|
|
109
141
|
"category": "meta",
|
|
110
142
|
"graphMethod": "GET",
|
|
111
143
|
"graphPathTemplate": "(local) reads {path} from the local filesystem; not a Graph endpoint",
|
|
@@ -130,6 +162,19 @@
|
|
|
130
162
|
]
|
|
131
163
|
}
|
|
132
164
|
},
|
|
165
|
+
{
|
|
166
|
+
"name": "keep-quoted",
|
|
167
|
+
"key": "keepQuoted",
|
|
168
|
+
"required": false,
|
|
169
|
+
"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`.",
|
|
170
|
+
"argumentHint": {
|
|
171
|
+
"kind": "magicValue",
|
|
172
|
+
"values": [
|
|
173
|
+
"true",
|
|
174
|
+
"false"
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
},
|
|
133
178
|
{
|
|
134
179
|
"name": "inline-images",
|
|
135
180
|
"key": "inlineImages",
|
|
@@ -163,13 +208,13 @@
|
|
|
163
208
|
"description": "Per-sheet cell cap (positive integer; default 50 000) for xlsx/csv sources. A sheet whose used range exceeds the cap renders as a truncation hint instead of a multi-hundred-MB table. No-op on other sources."
|
|
164
209
|
}
|
|
165
210
|
],
|
|
166
|
-
"example": "ask-marcel-office convert-local-file --path ./report.docx",
|
|
211
|
+
"example": "ask-marcel-office convert-local-file-to-markdown --path ./report.docx",
|
|
167
212
|
"responseShape": "`{ contentType: \"text/markdown\" | \"text/plain\", size, text }` for a single file; `{ count, files: [{ path, contentType, size, text } | { path, note }] }` for a `.zip` (one entry per contained file, unsupported entries noted). With `--include-images true` each `.zip` entry also carries `images: [{ path, contentType, sizeBytes, base64 }]` when it has extractable embedded images. A missing file returns api_error 404 with the path. Pair with the global `--output-path` to land the markdown on disk.",
|
|
168
213
|
"producesBytes": true
|
|
169
214
|
},
|
|
170
215
|
{
|
|
171
216
|
"name": "convert-mail-attachment-to-markdown",
|
|
172
|
-
"summary": "Convert an Outlook mail attachment to markdown. Polymorphic on the attachment’s `@odata.type`: fileAttachment decodes the inline bytes and runs them through the local conversion pipeline (docx via mammoth, xlsx via sheetjs, csv as markdown table, odt/ods/odp via content.xml, pptx as per-slide text (titles + bullets + speaker notes inline), pdf via text-layer extraction (unpdf → text/plain), legacy .xls via sheetjs and legacy .doc via word-extractor (text only), an Outlook .msg attachment rendered to markdown — headers + body with its own attachments converted recursively — plus plain-text passthrough); referenceAttachment resolves via /shares/{token}/driveItem and routes through the same dispatcher; itemAttachment (embedded mail / event / contact) is rendered locally via dedicated renderers. For pptx layout / images, `convert-mail-attachment-to-pdf` + a vision model reads the rendered deck better. A scanned / image-only PDF (no text layer), legacy .ppt, and rtf/etc. point to the PDF sibling. Loop/Fluid/Whiteboard reference-attachments use Graph `?format=html` (the four inputs Microsoft documents).",
|
|
217
|
+
"summary": "Convert an Outlook mail attachment to markdown. Polymorphic on the attachment’s `@odata.type`: fileAttachment decodes the inline bytes and runs them through the local conversion pipeline (docx via mammoth, xlsx via sheetjs, csv as markdown table, odt/ods/odp via content.xml, pptx as per-slide text (titles + bullets + speaker notes inline), pdf via text-layer extraction (unpdf → text/plain), legacy .xls via sheetjs and legacy .doc via word-extractor (text only), an Outlook .msg attachment rendered to markdown — headers + body (quoted reply chain stripped unless `--keep-quoted true`; inline `cid:` images shown as placeholders) with its own attachments converted recursively — plus plain-text passthrough); referenceAttachment resolves via /shares/{token}/driveItem and routes through the same dispatcher; itemAttachment (embedded mail / event / contact) is rendered locally via dedicated renderers. For pptx layout / images, `convert-mail-attachment-to-pdf` + a vision model reads the rendered deck better. A scanned / image-only PDF (no text layer), legacy .ppt, and rtf/etc. point to the PDF sibling. Loop/Fluid/Whiteboard reference-attachments use Graph `?format=html` (the four inputs Microsoft documents).",
|
|
173
218
|
"category": "mail",
|
|
174
219
|
"graphMethod": "GET",
|
|
175
220
|
"graphPathTemplate": "/me/messages/{message-id}/attachments/{attachment-id}",
|
|
@@ -199,6 +244,19 @@
|
|
|
199
244
|
"false"
|
|
200
245
|
]
|
|
201
246
|
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"name": "keep-quoted",
|
|
250
|
+
"key": "keepQuoted",
|
|
251
|
+
"required": false,
|
|
252
|
+
"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`.",
|
|
253
|
+
"argumentHint": {
|
|
254
|
+
"kind": "magicValue",
|
|
255
|
+
"values": [
|
|
256
|
+
"true",
|
|
257
|
+
"false"
|
|
258
|
+
]
|
|
259
|
+
}
|
|
202
260
|
}
|
|
203
261
|
],
|
|
204
262
|
"example": "ask-marcel-office convert-mail-attachment-to-markdown --message-id 'AAMkAD...' --attachment-id 'AAMkAD...attach1'",
|
|
@@ -231,8 +289,8 @@
|
|
|
231
289
|
"producesBytes": true
|
|
232
290
|
},
|
|
233
291
|
{
|
|
234
|
-
"name": "convert-mail-attachment-zip",
|
|
235
|
-
"summary": "Unzip a `.zip` Outlook mail attachment and convert every contained file in one call — the mail-side mirror of `convert-drive-item-zip`, 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).",
|
|
292
|
+
"name": "convert-mail-attachment-zip-to-markdown",
|
|
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).",
|
|
236
294
|
"category": "mail",
|
|
237
295
|
"graphMethod": "GET",
|
|
238
296
|
"graphPathTemplate": "/me/messages/{message-id}/attachments/{attachment-id}",
|
|
@@ -262,14 +320,27 @@
|
|
|
262
320
|
"false"
|
|
263
321
|
]
|
|
264
322
|
}
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"name": "keep-quoted",
|
|
326
|
+
"key": "keepQuoted",
|
|
327
|
+
"required": false,
|
|
328
|
+
"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`.",
|
|
329
|
+
"argumentHint": {
|
|
330
|
+
"kind": "magicValue",
|
|
331
|
+
"values": [
|
|
332
|
+
"true",
|
|
333
|
+
"false"
|
|
334
|
+
]
|
|
335
|
+
}
|
|
265
336
|
}
|
|
266
337
|
],
|
|
267
|
-
"example": "ask-marcel-office convert-mail-attachment-zip --message-id 'AAMkAD...' --attachment-id 'AAMkAD...attach1'",
|
|
338
|
+
"example": "ask-marcel-office convert-mail-attachment-zip-to-markdown --message-id 'AAMkAD...' --attachment-id 'AAMkAD...attach1'",
|
|
268
339
|
"responseShape": "`{ count, files: [{ path, contentType, size, text }] }` — one entry per file in the archive (sorted by path; non-mojibake names). Convertible files carry `{ contentType, size, text }` (the markdown); unsupported / failed entries carry `{ path, note }`. When the archive has more than 100 entries the response adds `truncated: true` + `totalEntries` and only the first 100 are converted. A non-fileAttachment (itemAttachment / referenceAttachment) or a non-zip payload returns an api_error."
|
|
269
340
|
},
|
|
270
341
|
{
|
|
271
342
|
"name": "convert-mail-to-markdown",
|
|
272
|
-
"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
|
|
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 (only if `hasAttachments:true`), 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.",
|
|
273
344
|
"category": "mail",
|
|
274
345
|
"graphMethod": "GET",
|
|
275
346
|
"graphPathTemplate": "/me/messages/{message-id}",
|
|
@@ -279,25 +350,19 @@
|
|
|
279
350
|
"name": "message-id",
|
|
280
351
|
"key": "messageId",
|
|
281
352
|
"required": true,
|
|
282
|
-
"
|
|
283
|
-
{
|
|
284
|
-
"name": "id",
|
|
285
|
-
"key": "id"
|
|
286
|
-
}
|
|
287
|
-
],
|
|
288
|
-
"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`."
|
|
289
354
|
},
|
|
290
355
|
{
|
|
291
356
|
"name": "inline-images",
|
|
292
357
|
"key": "inlineImages",
|
|
293
358
|
"required": false,
|
|
294
|
-
"description": "Pass `--inline-images
|
|
359
|
+
"description": "Pass `--inline-images true` to fetch small inline images (≤ 2 MB, `image/*` only) and embed them as base64 `data:` URIs. Default is `false` (text-first): no per-image bytes fetch, and every inline `cid:` image renders as a `[inline image: <name>]` placeholder while still appearing in the file-attachments list, so the LLM caller sees what exists and can fetch any specific image via `get-mail-attachment` on demand. Embedding a 6-inline-image email inflated a 6 KB body to ~36 KB; the default keeps it near 6 KB."
|
|
295
360
|
},
|
|
296
361
|
{
|
|
297
362
|
"name": "keep-quoted",
|
|
298
363
|
"key": "keepQuoted",
|
|
299
364
|
"required": false,
|
|
300
|
-
"description": "Quoted reply chains and forwarded-message blocks are stripped by default (they duplicate content already present in earlier messages and inflate the context budget). The stripped tail is replaced with a single visible marker naming this flag, so nothing is removed silently. Pass `--keep-quoted true` to preserve the full body. Only well-known structural markers are cut: in HTML bodies Outlook `divRplyFwdMsg` / `appendonsend` / `stopSpelling` and
|
|
365
|
+
"description": "Quoted reply chains and forwarded-message blocks are stripped by default (they duplicate content already present in earlier messages and inflate the context budget). The stripped tail is replaced with a single visible marker naming this flag, so nothing is removed silently. Pass `--keep-quoted true` to preserve the full body. Only well-known structural markers are cut: in HTML bodies Outlook `divRplyFwdMsg` / `appendonsend` / `stopSpelling`, Gmail `gmail_quote`, the Outlook reply border separator (`#E1E1E1` on desktop, `#B5C4DF` on Mac/mobile), and a bold `From:`/`Sent:` header-label pair (localized variants recognized: 发件人/发送时间, De/Envoyé, Von/Gesendet, Da/Inviato, De/Enviado, Van/Verzonden, 差出人/送信日時, 보낸 사람/보낸 날짜 — a lone bolded \"From:\" without its companion label never cuts); in plain-text bodies the `Original Message` banner, the `On … wrote:` attribution line, leading `>` quote lines, and the same localized `From:`+`Sent:` line pairs.",
|
|
301
366
|
"argumentHint": {
|
|
302
367
|
"kind": "magicValue",
|
|
303
368
|
"values": [
|
|
@@ -323,13 +388,7 @@
|
|
|
323
388
|
"name": "forward-message-id",
|
|
324
389
|
"key": "forwardMessageId",
|
|
325
390
|
"required": true,
|
|
326
|
-
"
|
|
327
|
-
{
|
|
328
|
-
"name": "id",
|
|
329
|
-
"key": "id"
|
|
330
|
-
}
|
|
331
|
-
],
|
|
332
|
-
"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.",
|
|
333
392
|
"argumentHint": {
|
|
334
393
|
"kind": "idOrName"
|
|
335
394
|
}
|
|
@@ -347,26 +406,39 @@
|
|
|
347
406
|
"description": "Comma-separated list of CC recipient email addresses."
|
|
348
407
|
},
|
|
349
408
|
{
|
|
350
|
-
"name": "
|
|
351
|
-
"key": "
|
|
409
|
+
"name": "comment",
|
|
410
|
+
"key": "comment",
|
|
352
411
|
"required": true,
|
|
353
|
-
"description": "The comment text, placed above the quoted forwarded message
|
|
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."
|
|
354
413
|
},
|
|
355
414
|
{
|
|
356
415
|
"name": "subject",
|
|
357
416
|
"key": "subject",
|
|
358
417
|
"required": false,
|
|
359
418
|
"description": "Optional subject override. Omit to keep the inherited \"FW: ...\" subject."
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"name": "body-content-type",
|
|
422
|
+
"key": "bodyContentType",
|
|
423
|
+
"required": false,
|
|
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.",
|
|
425
|
+
"argumentHint": {
|
|
426
|
+
"kind": "magicValue",
|
|
427
|
+
"values": [
|
|
428
|
+
"Text",
|
|
429
|
+
"HTML"
|
|
430
|
+
]
|
|
431
|
+
}
|
|
360
432
|
}
|
|
361
433
|
],
|
|
362
|
-
"example": "ask-marcel-office create-forward-draft --forward-message-id \"AAMkAD...\" --to-recipients \"bob@example.com\" --
|
|
363
|
-
"responseShape": "
|
|
364
|
-
"bodyTemplate": "POST { comment: '{body-content}', toRecipients: '{to-recipients}' } then
|
|
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.\"",
|
|
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`.",
|
|
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}' }",
|
|
365
437
|
"mutates": true
|
|
366
438
|
},
|
|
367
439
|
{
|
|
368
440
|
"name": "create-mail-draft",
|
|
369
|
-
"summary": "Create a new mail draft. POST /me/messages (or /me/mailFolders/{id}/messages when --mail-folder-id is set). The draft is saved in the Drafts folder (or the specified folder) and can be sent later via the Outlook client or Graph sendMail. Recipients are comma-separated email addresses. Returns the
|
|
441
|
+
"summary": "Create a new mail draft. POST /me/messages (or /me/mailFolders/{id}/messages when --mail-folder-id is set). The draft is saved in the Drafts folder (or the specified folder) and can be sent later via the Outlook client or Graph sendMail. Recipients are comma-separated email addresses. Returns a slim confirmation (id, subject, recipients, importance, bodyPreview, …) - NOT the body you just wrote; read the full draft back with get-mail-message if you need it. Use the returned id with update-mail-draft to modify before sending.",
|
|
370
442
|
"category": "mail",
|
|
371
443
|
"graphMethod": "POST",
|
|
372
444
|
"graphPathTemplate": "/me/messages (or /me/mailFolders/{mail-folder-id}/messages)",
|
|
@@ -440,49 +512,69 @@
|
|
|
440
512
|
}
|
|
441
513
|
],
|
|
442
514
|
"example": "ask-marcel-office create-mail-draft --subject \"Q3 Report\" --body-content \"Please review the attached report.\" --to-recipients \"alice@example.com,bob@example.com\" --importance High",
|
|
443
|
-
"responseShape": "
|
|
515
|
+
"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 supplied it; read it back with `get-mail-message --id <the returned id>` if you need it. The `id` is the draft — modify it with `update-mail-draft` before sending.",
|
|
444
516
|
"bodyTemplate": "{ subject: '{subject}', body: { contentType: '{body-content-type}', content: '{body-content}' }, toRecipients: '{to-recipients}', ccRecipients: '{cc-recipients}', bccRecipients: '{bcc-recipients}', importance: '{importance}' }",
|
|
445
517
|
"mutates": true
|
|
446
518
|
},
|
|
447
519
|
{
|
|
448
520
|
"name": "create-reply-draft",
|
|
449
|
-
"summary": "Create an UNSENT reply
|
|
521
|
+
"summary": "Create an UNSENT reply draft threaded on an existing message. POST /me/messages/{id}/createReplyAll mints the draft (inherited recipients, RE: subject, quoted history) with your reply text placed above the quote, in one call. Reply-all by default - dropping recipients is a deliberate act, so pass --reply-all false to reply to the sender only, which switches the action to createReply. The draft is saved in Drafts and can be reviewed, edited, and sent from any Outlook client; the CLI still cannot send.",
|
|
450
522
|
"category": "mail",
|
|
451
523
|
"graphMethod": "POST",
|
|
452
|
-
"graphPathTemplate": "/me/messages/{reply-to-message-id}/createReplyAll (+ optional body-free PATCH for subject)",
|
|
524
|
+
"graphPathTemplate": "/me/messages/{reply-to-message-id}/createReplyAll, or /createReply when {reply-all} is false (+ optional body-free PATCH for subject)",
|
|
453
525
|
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/message-createreplyall",
|
|
454
526
|
"options": [
|
|
455
527
|
{
|
|
456
528
|
"name": "reply-to-message-id",
|
|
457
529
|
"key": "replyToMessageId",
|
|
458
530
|
"required": true,
|
|
459
|
-
"
|
|
460
|
-
{
|
|
461
|
-
"name": "id",
|
|
462
|
-
"key": "id"
|
|
463
|
-
}
|
|
464
|
-
],
|
|
465
|
-
"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.",
|
|
466
532
|
"argumentHint": {
|
|
467
533
|
"kind": "idOrName"
|
|
468
534
|
}
|
|
469
535
|
},
|
|
470
536
|
{
|
|
471
|
-
"name": "
|
|
472
|
-
"key": "
|
|
537
|
+
"name": "comment",
|
|
538
|
+
"key": "comment",
|
|
473
539
|
"required": true,
|
|
474
|
-
"description": "The reply text, placed above the quoted history
|
|
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."
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"name": "body-content-type",
|
|
544
|
+
"key": "bodyContentType",
|
|
545
|
+
"required": false,
|
|
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.",
|
|
547
|
+
"argumentHint": {
|
|
548
|
+
"kind": "magicValue",
|
|
549
|
+
"values": [
|
|
550
|
+
"Text",
|
|
551
|
+
"HTML"
|
|
552
|
+
]
|
|
553
|
+
}
|
|
475
554
|
},
|
|
476
555
|
{
|
|
477
556
|
"name": "subject",
|
|
478
557
|
"key": "subject",
|
|
479
558
|
"required": false,
|
|
480
559
|
"description": "Optional subject override. Omit to keep the inherited \"RE: ...\" subject."
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"name": "reply-all",
|
|
563
|
+
"key": "replyAll",
|
|
564
|
+
"required": false,
|
|
565
|
+
"description": "Who the draft replies to. Defaults to true (everyone on the thread: sender + To + Cc, via createReplyAll). Pass `false` to reply to the sender only, via createReply. Only an explicit `false` narrows the recipients - anything else keeps reply-all.",
|
|
566
|
+
"argumentHint": {
|
|
567
|
+
"kind": "magicValue",
|
|
568
|
+
"values": [
|
|
569
|
+
"true",
|
|
570
|
+
"false"
|
|
571
|
+
]
|
|
572
|
+
}
|
|
481
573
|
}
|
|
482
574
|
],
|
|
483
|
-
"example": "ask-marcel-office create-reply-draft --reply-to-message-id \"AAMkAD...\" --
|
|
484
|
-
"responseShape": "
|
|
485
|
-
"bodyTemplate": "POST { comment: '{body-content}' } then
|
|
575
|
+
"example": "ask-marcel-office create-reply-draft --reply-to-message-id \"AAMkAD...\" --comment \"Confirmed for Contoso, aligned with the group choice.\"",
|
|
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`.",
|
|
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}' }",
|
|
486
578
|
"mutates": true
|
|
487
579
|
},
|
|
488
580
|
{
|
|
@@ -505,6 +597,12 @@
|
|
|
505
597
|
"required": true,
|
|
506
598
|
"description": "driveItem ID of the file to convert. Returned by `list-folder-files` or `search-onedrive-files`."
|
|
507
599
|
},
|
|
600
|
+
{
|
|
601
|
+
"name": "tenant-id",
|
|
602
|
+
"key": "tenantId",
|
|
603
|
+
"required": false,
|
|
604
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
605
|
+
},
|
|
508
606
|
{
|
|
509
607
|
"name": "include-metadata",
|
|
510
608
|
"key": "includeMetadata",
|
|
@@ -518,6 +616,19 @@
|
|
|
518
616
|
]
|
|
519
617
|
}
|
|
520
618
|
},
|
|
619
|
+
{
|
|
620
|
+
"name": "keep-quoted",
|
|
621
|
+
"key": "keepQuoted",
|
|
622
|
+
"required": false,
|
|
623
|
+
"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`.",
|
|
624
|
+
"argumentHint": {
|
|
625
|
+
"kind": "magicValue",
|
|
626
|
+
"values": [
|
|
627
|
+
"true",
|
|
628
|
+
"false"
|
|
629
|
+
]
|
|
630
|
+
}
|
|
631
|
+
},
|
|
521
632
|
{
|
|
522
633
|
"name": "inline-images",
|
|
523
634
|
"key": "inlineImages",
|
|
@@ -561,6 +672,12 @@
|
|
|
561
672
|
"key": "itemId",
|
|
562
673
|
"required": true,
|
|
563
674
|
"description": "driveItem ID of the file to convert. Returned by `list-folder-files` or `search-onedrive-files`."
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
"name": "tenant-id",
|
|
678
|
+
"key": "tenantId",
|
|
679
|
+
"required": false,
|
|
680
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
564
681
|
}
|
|
565
682
|
],
|
|
566
683
|
"example": "ask-marcel-office download-drive-item-as-pdf --drive-id 'b!1234' --item-id '01ABC'",
|
|
@@ -571,9 +688,6 @@
|
|
|
571
688
|
"name": "download-drive-item-content",
|
|
572
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.",
|
|
573
690
|
"category": "drive",
|
|
574
|
-
"commandAliases": [
|
|
575
|
-
"download-onedrive-file-content"
|
|
576
|
-
],
|
|
577
691
|
"graphMethod": "GET",
|
|
578
692
|
"graphPathTemplate": "/drives/{drive-id}/items/{item-id}/content",
|
|
579
693
|
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/driveitem-get-content",
|
|
@@ -589,6 +703,12 @@
|
|
|
589
703
|
"key": "itemId",
|
|
590
704
|
"required": true,
|
|
591
705
|
"description": "driveItem ID of the file to download. Returned by `ask-marcel-office list-folder-files` (works on SharePoint library drives too) or `search-onedrive-files`."
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
"name": "tenant-id",
|
|
709
|
+
"key": "tenantId",
|
|
710
|
+
"required": false,
|
|
711
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
592
712
|
}
|
|
593
713
|
],
|
|
594
714
|
"example": "ask-marcel-office download-drive-item-content --drive-id 'b!1234' --item-id '01ABC'",
|
|
@@ -673,6 +793,12 @@
|
|
|
673
793
|
"key": "itemId",
|
|
674
794
|
"required": true,
|
|
675
795
|
"description": "driveItem ID of the pdf / docx / xlsx / pptx file. Returned by `list-folder-files` or `search-onedrive-files`."
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
"name": "tenant-id",
|
|
799
|
+
"key": "tenantId",
|
|
800
|
+
"required": false,
|
|
801
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
676
802
|
}
|
|
677
803
|
],
|
|
678
804
|
"example": "ask-marcel-office extract-drive-item-images --drive-id 'b!1234' --item-id '01ABC' --output-dir ./deck-images",
|
|
@@ -681,7 +807,7 @@
|
|
|
681
807
|
},
|
|
682
808
|
{
|
|
683
809
|
"name": "extract-local-file-images",
|
|
684
|
-
"summary": "Extract the embedded images from a file ON DISK — the local sibling of `extract-drive-item-images`, and like `convert-local-file` it never calls Microsoft Graph (works offline, no login). Same per-extension dispatch: docx / xlsx / pptx (and their macro-enabled / template variants) have their OOXML media parts read directly (png/jpg/gif/bmp/tiff/webp/svg — full-resolution originals, including images on hidden slides); a pdf is walked page by page via unpdf with each painted image re-encoded as PNG. Two flows only this command completes: a Graph-rendered PDF saved locally (legacy `.ppt` → `download-drive-item-as-pdf` with the global output-path flag → this command pulls the slide images for OCR), and Office files unpacked from a local archive. Pair with the global output-dir flag to write every image to a folder; otherwise the bytes ride back base64-encoded. Any other extension returns a 415 naming the local ways out.",
|
|
810
|
+
"summary": "Extract the embedded images from a file ON DISK — the local sibling of `extract-drive-item-images`, and like `convert-local-file-to-markdown` it never calls Microsoft Graph (works offline, no login). Same per-extension dispatch: docx / xlsx / pptx (and their macro-enabled / template variants) have their OOXML media parts read directly (png/jpg/gif/bmp/tiff/webp/svg — full-resolution originals, including images on hidden slides); a pdf is walked page by page via unpdf with each painted image re-encoded as PNG. Two flows only this command completes: a Graph-rendered PDF saved locally (legacy `.ppt` → `download-drive-item-as-pdf` with the global output-path flag → this command pulls the slide images for OCR), and Office files unpacked from a local archive. Pair with the global output-dir flag to write every image to a folder; otherwise the bytes ride back base64-encoded. Any other extension returns a 415 naming the local ways out.",
|
|
685
811
|
"category": "meta",
|
|
686
812
|
"graphMethod": "GET",
|
|
687
813
|
"graphPathTemplate": "(local) reads {path} from the local filesystem; not a Graph endpoint",
|
|
@@ -759,13 +885,7 @@
|
|
|
759
885
|
"name": "message-id",
|
|
760
886
|
"key": "messageId",
|
|
761
887
|
"required": true,
|
|
762
|
-
"
|
|
763
|
-
{
|
|
764
|
-
"name": "id",
|
|
765
|
-
"key": "id"
|
|
766
|
-
}
|
|
767
|
-
],
|
|
768
|
-
"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`."
|
|
769
889
|
}
|
|
770
890
|
],
|
|
771
891
|
"example": "ask-marcel-office extract-sharepoint-links-in-mail --message-id 'AAMkADk0...'",
|
|
@@ -800,9 +920,33 @@
|
|
|
800
920
|
],
|
|
801
921
|
"example": "ask-marcel-office find-chats-with-user --name 'Alex Kim'",
|
|
802
922
|
"responseShape": "`{ name, matches: [{ chatId, title, chatType, threadType, memberCount, lastMessageAt?, matchedMembers: [{ mri, displayName, email, userSubType }] }], matchCount, pagesFetched, chatsScanned, chatsHydrated, unresolvedMemberCount, hasMore, nextContinuationToken?, hint? }`. `matchedMembers` always carries the matching entries' identifying fields — pass `chatId` into `list-teams-chat-history` to read message bodies. `chatsHydrated` counts the per-chat members lookups spent resolving bare cross-tenant members in direct (1:1) chats. `unresolvedMemberCount` is how many cross-tenant members are still unresolved by name (bare members in group/meeting chats, which are not deep-probed, plus any 1:1 hydration that errored); when `matchCount` is 0 and this is non-zero, a `hint` is present explaining the likely cause and the object-id / read-by-chat-id remedy — so an empty result is never silently confident. `hasMore: true` means `--max-pages` was hit before exhausting the chat list; chain with the existing `--continuation-token` flag on `list-teams-chats-with-messages` if you need to scan further (this command does not advertise a `--continuation-token` because resuming a partial search is rare; users either widen `--max-pages` or refine `--name`).",
|
|
803
|
-
"needsSubstrateToken":
|
|
923
|
+
"needsSubstrateToken": "chatsvcagg",
|
|
804
924
|
"stability": "experimental"
|
|
805
925
|
},
|
|
926
|
+
{
|
|
927
|
+
"name": "find-mail-drafts",
|
|
928
|
+
"summary": "Find existing drafts on a mail thread WITHOUT trusting a conversationId $filter. Reply and forward drafts do not always inherit the inbound message conversationId (a thread can split across several), and Graph $filter on the Drafts folder is not read-your-writes consistent, so filtering Drafts by conversationId misses drafts. This command instead scans the 50 most recently modified drafts and matches them client-side on a normalized subject (stripping RE:/FW: and localized reply/forward prefixes) plus, optionally, a shared recipient. Use it before create-reply-draft to avoid creating a duplicate: if a match comes back, revise it with update-mail-draft instead of making a new one. Read-only.",
|
|
929
|
+
"category": "mail",
|
|
930
|
+
"graphMethod": "GET",
|
|
931
|
+
"graphPathTemplate": "/me/mailFolders/drafts/messages?$top=50&$orderby=lastModifiedDateTime desc&$select=id,subject,toRecipients,ccRecipients,conversationId,lastModifiedDateTime,webLink (a read-only scan of the 50 most recently modified drafts; each is matched CLIENT-SIDE on a normalized {subject} and, when given, a shared {to-recipients} address, so neither value is sent to Graph)",
|
|
932
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/mailfolder-list-messages",
|
|
933
|
+
"options": [
|
|
934
|
+
{
|
|
935
|
+
"name": "subject",
|
|
936
|
+
"key": "subject",
|
|
937
|
+
"required": true,
|
|
938
|
+
"description": "The thread subject to match. Reply and forward prefixes (RE:, FW:, and localized variants) are stripped on both sides before comparing, so \"Contoso Q3\" matches a draft titled \"RE: Contoso Q3\"."
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
"name": "to-recipients",
|
|
942
|
+
"key": "toRecipients",
|
|
943
|
+
"required": false,
|
|
944
|
+
"description": "Optional comma-separated recipient addresses. When given, a draft matches only if it shares at least one To or Cc address with this list, narrowing subject-only collisions."
|
|
945
|
+
}
|
|
946
|
+
],
|
|
947
|
+
"example": "ask-marcel-office find-mail-drafts --subject \"Contoso Q3 budget\" --to-recipients \"kim@example.com\"",
|
|
948
|
+
"responseShape": "`{ matches: message[], conversationIds: string[], scanned: number, scanLimit: number }`. `matches` are the drafts whose normalized subject (RE:/FW:/localized prefixes stripped) equals yours, each carrying `{ id, subject, toRecipients, ccRecipients, conversationId, lastModifiedDateTime, webLink }`; pass a match `id` to update-mail-draft to revise it instead of creating a duplicate. `conversationIds` is the de-duplicated union of conversationIds across the matches (a thread can span several). `scanned` is how many drafts were examined and `scanLimit` the cap (50): when `scanned` equals `scanLimit`, older drafts may exist beyond the window."
|
|
949
|
+
},
|
|
806
950
|
{
|
|
807
951
|
"name": "get-calendar-event",
|
|
808
952
|
"summary": "Fetch a single calendar event by ID from the signed-in user’s default calendar. Pass `--select` to project only the fields you need (the full event body can be large with HTML body and attendee lists).",
|
|
@@ -815,12 +959,6 @@
|
|
|
815
959
|
"name": "event-id",
|
|
816
960
|
"key": "eventId",
|
|
817
961
|
"required": true,
|
|
818
|
-
"aliases": [
|
|
819
|
-
{
|
|
820
|
-
"name": "id",
|
|
821
|
-
"key": "id"
|
|
822
|
-
}
|
|
823
|
-
],
|
|
824
962
|
"description": "Microsoft Graph event ID. Returned by `ask-marcel-office list-calendar-events` in the `id` field of each event."
|
|
825
963
|
},
|
|
826
964
|
{
|
|
@@ -887,12 +1025,6 @@
|
|
|
887
1025
|
"name": "chat-id",
|
|
888
1026
|
"key": "chatId",
|
|
889
1027
|
"required": true,
|
|
890
|
-
"aliases": [
|
|
891
|
-
{
|
|
892
|
-
"name": "id",
|
|
893
|
-
"key": "id"
|
|
894
|
-
}
|
|
895
|
-
],
|
|
896
1028
|
"description": "Microsoft Teams chat ID, e.g. `19:abc...@thread.v2`. Returned by `list-chats`."
|
|
897
1029
|
},
|
|
898
1030
|
{
|
|
@@ -954,13 +1086,7 @@
|
|
|
954
1086
|
"name": "item-id",
|
|
955
1087
|
"key": "itemId",
|
|
956
1088
|
"required": true,
|
|
957
|
-
"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.
|
|
958
|
-
"aliases": [
|
|
959
|
-
{
|
|
960
|
-
"name": "folder-id",
|
|
961
|
-
"key": "folderId"
|
|
962
|
-
}
|
|
963
|
-
]
|
|
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."
|
|
964
1090
|
},
|
|
965
1091
|
{
|
|
966
1092
|
"name": "top",
|
|
@@ -974,18 +1100,6 @@
|
|
|
974
1100
|
"required": false,
|
|
975
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`."
|
|
976
1102
|
},
|
|
977
|
-
{
|
|
978
|
-
"name": "filter",
|
|
979
|
-
"key": "filter",
|
|
980
|
-
"required": false,
|
|
981
|
-
"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."
|
|
982
|
-
},
|
|
983
|
-
{
|
|
984
|
-
"name": "orderby",
|
|
985
|
-
"key": "orderby",
|
|
986
|
-
"required": false,
|
|
987
|
-
"description": "OData $orderby: sort expression with optional asc/desc (e.g. `receivedDateTime desc`). Some Graph filter combinations are rejected; remove $orderby if InefficientFilter occurs."
|
|
988
|
-
},
|
|
989
1103
|
{
|
|
990
1104
|
"name": "expand",
|
|
991
1105
|
"key": "expand",
|
|
@@ -1017,6 +1131,12 @@
|
|
|
1017
1131
|
"required": true,
|
|
1018
1132
|
"description": "driveItem ID. Returned by `list-folder-files`, `search-onedrive-files`, or `get-drive-root-item`."
|
|
1019
1133
|
},
|
|
1134
|
+
{
|
|
1135
|
+
"name": "tenant-id",
|
|
1136
|
+
"key": "tenantId",
|
|
1137
|
+
"required": false,
|
|
1138
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
1139
|
+
},
|
|
1020
1140
|
{
|
|
1021
1141
|
"name": "select",
|
|
1022
1142
|
"key": "select",
|
|
@@ -1160,6 +1280,12 @@
|
|
|
1160
1280
|
"key": "expand",
|
|
1161
1281
|
"required": false,
|
|
1162
1282
|
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
"name": "tenant-id",
|
|
1286
|
+
"key": "tenantId",
|
|
1287
|
+
"required": false,
|
|
1288
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
1163
1289
|
}
|
|
1164
1290
|
],
|
|
1165
1291
|
"example": "ask-marcel-office get-drive-item-list-item --drive-id 'b!1234' --item-id '01ABC'",
|
|
@@ -1185,18 +1311,6 @@
|
|
|
1185
1311
|
"required": false,
|
|
1186
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`."
|
|
1187
1313
|
},
|
|
1188
|
-
{
|
|
1189
|
-
"name": "filter",
|
|
1190
|
-
"key": "filter",
|
|
1191
|
-
"required": false,
|
|
1192
|
-
"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."
|
|
1193
|
-
},
|
|
1194
|
-
{
|
|
1195
|
-
"name": "orderby",
|
|
1196
|
-
"key": "orderby",
|
|
1197
|
-
"required": false,
|
|
1198
|
-
"description": "OData $orderby: sort expression with optional asc/desc (e.g. `receivedDateTime desc`). Some Graph filter combinations are rejected; remove $orderby if InefficientFilter occurs."
|
|
1199
|
-
},
|
|
1200
1314
|
{
|
|
1201
1315
|
"name": "expand",
|
|
1202
1316
|
"key": "expand",
|
|
@@ -1220,12 +1334,6 @@
|
|
|
1220
1334
|
"name": "drive-id",
|
|
1221
1335
|
"key": "driveId",
|
|
1222
1336
|
"required": true,
|
|
1223
|
-
"aliases": [
|
|
1224
|
-
{
|
|
1225
|
-
"name": "id",
|
|
1226
|
-
"key": "id"
|
|
1227
|
-
}
|
|
1228
|
-
],
|
|
1229
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."
|
|
1230
1338
|
},
|
|
1231
1339
|
{
|
|
@@ -1446,12 +1554,6 @@
|
|
|
1446
1554
|
"name": "group-id",
|
|
1447
1555
|
"key": "groupId",
|
|
1448
1556
|
"required": true,
|
|
1449
|
-
"aliases": [
|
|
1450
|
-
{
|
|
1451
|
-
"name": "id",
|
|
1452
|
-
"key": "id"
|
|
1453
|
-
}
|
|
1454
|
-
],
|
|
1455
1557
|
"description": "Azure AD group object ID. Use `list-groups` to find one."
|
|
1456
1558
|
},
|
|
1457
1559
|
{
|
|
@@ -1509,7 +1611,7 @@
|
|
|
1509
1611
|
},
|
|
1510
1612
|
{
|
|
1511
1613
|
"name": "get-mail-message",
|
|
1512
|
-
"summary": "Get a single Outlook message by ID. The CLI ships a slim default `--select=id,subject,from,toRecipients,ccRecipients,receivedDateTime,hasAttachments,isRead,importance,bodyPreview` so an LLM caller doesn't pull a 41 KB resource just to read a subject line. Pass `--select id,subject,body` (or any other comma-separated field list) to override; for the raw RFC-822 source use `get-mail-message-mime` instead.",
|
|
1614
|
+
"summary": "Get a single Outlook message by ID. The CLI ships a slim default `--select=id,subject,from,toRecipients,ccRecipients,receivedDateTime,hasAttachments,isRead,importance,bodyPreview,conversationId` (`conversationId` gives you the thread, e.g. for `list-conversation-messages`) so an LLM caller doesn't pull a 41 KB resource just to read a subject line. Pass `--select id,subject,body` (or any other comma-separated field list) to override; for the raw RFC-822 source use `get-mail-message-mime` instead.",
|
|
1513
1615
|
"category": "mail",
|
|
1514
1616
|
"graphMethod": "GET",
|
|
1515
1617
|
"graphPathTemplate": "/me/messages/{message-id}",
|
|
@@ -1519,13 +1621,7 @@
|
|
|
1519
1621
|
"name": "message-id",
|
|
1520
1622
|
"key": "messageId",
|
|
1521
1623
|
"required": true,
|
|
1522
|
-
"
|
|
1523
|
-
{
|
|
1524
|
-
"name": "id",
|
|
1525
|
-
"key": "id"
|
|
1526
|
-
}
|
|
1527
|
-
],
|
|
1528
|
-
"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`."
|
|
1529
1625
|
},
|
|
1530
1626
|
{
|
|
1531
1627
|
"name": "select",
|
|
@@ -1555,13 +1651,7 @@
|
|
|
1555
1651
|
"name": "message-id",
|
|
1556
1652
|
"key": "messageId",
|
|
1557
1653
|
"required": true,
|
|
1558
|
-
"
|
|
1559
|
-
{
|
|
1560
|
-
"name": "id",
|
|
1561
|
-
"key": "id"
|
|
1562
|
-
}
|
|
1563
|
-
],
|
|
1564
|
-
"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`."
|
|
1565
1655
|
}
|
|
1566
1656
|
],
|
|
1567
1657
|
"example": "ask-marcel-office get-mail-message-mime --message-id 'AAMkAD...'",
|
|
@@ -1586,22 +1676,34 @@
|
|
|
1586
1676
|
"name": "message-rule-id",
|
|
1587
1677
|
"key": "messageRuleId",
|
|
1588
1678
|
"required": true,
|
|
1589
|
-
"description": "Message rule ID. Returned by `list-mail-rules`."
|
|
1590
|
-
"aliases": [
|
|
1591
|
-
{
|
|
1592
|
-
"name": "id",
|
|
1593
|
-
"key": "id"
|
|
1594
|
-
},
|
|
1595
|
-
{
|
|
1596
|
-
"name": "rule-id",
|
|
1597
|
-
"key": "ruleId"
|
|
1598
|
-
}
|
|
1599
|
-
]
|
|
1679
|
+
"description": "Message rule ID. Returned by `list-mail-rules`."
|
|
1600
1680
|
}
|
|
1601
1681
|
],
|
|
1602
1682
|
"example": "ask-marcel-office get-mail-rule --message-rule-id 'AQAAANC...'",
|
|
1603
1683
|
"responseShape": "single Microsoft Graph `messageRule` resource"
|
|
1604
1684
|
},
|
|
1685
|
+
{
|
|
1686
|
+
"name": "get-mail-signature",
|
|
1687
|
+
"summary": "Read your own email signature as HTML, lifted from a message you already sent. Graph-created drafts carry NO signature (create-mail-draft, create-reply-draft, and create-forward-draft all produce unsigned bodies), so this is where you get one: take the `text` this returns, append it to your reply text, and hand the result to `update-mail-draft` in comment mode (HTML body-content-type) to place it above the quoted history. Scans your last 10 sent messages newest-first and returns the first `<div id=\"Signature\">` block it finds, stopping there, with any logo the block references embedded as a base64 data: URI so the HTML renders on its own. Read-only. NOTE: the marker is written by Outlook on the web and new Outlook; mail composed in Outlook desktop does not carry it, so pin a webmail-sent message with --message-id if the scan finds nothing.",
|
|
1688
|
+
"category": "mail",
|
|
1689
|
+
"graphMethod": "GET",
|
|
1690
|
+
"graphPathTemplate": "/me/mailFolders/sentitems/messages (scan, skipped when {message-id} is given) then /me/messages/{message-id}?$select=body,sentDateTime,hasAttachments (+ /attachments per referenced logo)",
|
|
1691
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/message-get",
|
|
1692
|
+
"options": [
|
|
1693
|
+
{
|
|
1694
|
+
"name": "message-id",
|
|
1695
|
+
"key": "messageId",
|
|
1696
|
+
"required": false,
|
|
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.",
|
|
1698
|
+
"argumentHint": {
|
|
1699
|
+
"kind": "idOrName"
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
],
|
|
1703
|
+
"example": "ask-marcel-office get-mail-signature",
|
|
1704
|
+
"responseShape": "`{ contentType: \"text/html\", size, text, sourceMessageId, sentDateTime?, inlinedImages, note? }`. `text` is the signature block itself (the `<div id=\"Signature\">` element, not the whole body), ready to append to a reply. `inlinedImages` counts the logos embedded as data: URIs; any image too large (> 2 MB) or unfetchable keeps its raw `cid:` reference and is named in `note` — no placeholder is substituted, so the reference stays resolvable via get-mail-attachment. `--output-path` writes the HTML to a file.",
|
|
1705
|
+
"producesBytes": true
|
|
1706
|
+
},
|
|
1605
1707
|
{
|
|
1606
1708
|
"name": "get-mailbox-settings",
|
|
1607
1709
|
"summary": "Get the signed-in user's Outlook mailbox settings (timezone, working hours, automatic replies). Note: Graph silently ignores `$select` / `$expand` on this endpoint, so the CLI does NOT expose them — the full payload (including the auto-reply HTML body) is always returned. Slim client-side if you only need a subset.",
|
|
@@ -1685,17 +1787,7 @@
|
|
|
1685
1787
|
"name": "onenote-page-id",
|
|
1686
1788
|
"key": "onenotePageId",
|
|
1687
1789
|
"required": true,
|
|
1688
|
-
"description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
|
|
1689
|
-
"aliases": [
|
|
1690
|
-
{
|
|
1691
|
-
"name": "id",
|
|
1692
|
-
"key": "id"
|
|
1693
|
-
},
|
|
1694
|
-
{
|
|
1695
|
-
"name": "page-id",
|
|
1696
|
-
"key": "pageId"
|
|
1697
|
-
}
|
|
1698
|
-
]
|
|
1790
|
+
"description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
|
|
1699
1791
|
},
|
|
1700
1792
|
{
|
|
1701
1793
|
"name": "inline-images",
|
|
@@ -1740,17 +1832,7 @@
|
|
|
1740
1832
|
"name": "onenote-page-id",
|
|
1741
1833
|
"key": "onenotePageId",
|
|
1742
1834
|
"required": true,
|
|
1743
|
-
"description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
|
|
1744
|
-
"aliases": [
|
|
1745
|
-
{
|
|
1746
|
-
"name": "id",
|
|
1747
|
-
"key": "id"
|
|
1748
|
-
},
|
|
1749
|
-
{
|
|
1750
|
-
"name": "page-id",
|
|
1751
|
-
"key": "pageId"
|
|
1752
|
-
}
|
|
1753
|
-
]
|
|
1835
|
+
"description": "OneNote page ID. Returned by `ask-marcel-office list-onenote-section-pages`."
|
|
1754
1836
|
}
|
|
1755
1837
|
],
|
|
1756
1838
|
"example": "ask-marcel-office get-onenote-page-content --onenote-page-id '1-abc...'",
|
|
@@ -1793,17 +1875,7 @@
|
|
|
1793
1875
|
"name": "planner-bucket-id",
|
|
1794
1876
|
"key": "plannerBucketId",
|
|
1795
1877
|
"required": true,
|
|
1796
|
-
"description": "Planner bucket ID. Returned by `ask-marcel-office list-plan-buckets`."
|
|
1797
|
-
"aliases": [
|
|
1798
|
-
{
|
|
1799
|
-
"name": "id",
|
|
1800
|
-
"key": "id"
|
|
1801
|
-
},
|
|
1802
|
-
{
|
|
1803
|
-
"name": "bucket-id",
|
|
1804
|
-
"key": "bucketId"
|
|
1805
|
-
}
|
|
1806
|
-
]
|
|
1878
|
+
"description": "Planner bucket ID. Returned by `ask-marcel-office list-plan-buckets`."
|
|
1807
1879
|
}
|
|
1808
1880
|
],
|
|
1809
1881
|
"example": "ask-marcel-office get-planner-bucket --planner-bucket-id 'sFNeQRFu_kqhxpwwAhmA15gAGfoT'",
|
|
@@ -1821,17 +1893,7 @@
|
|
|
1821
1893
|
"name": "planner-plan-id",
|
|
1822
1894
|
"key": "plannerPlanId",
|
|
1823
1895
|
"required": true,
|
|
1824
|
-
"description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
|
|
1825
|
-
"aliases": [
|
|
1826
|
-
{
|
|
1827
|
-
"name": "id",
|
|
1828
|
-
"key": "id"
|
|
1829
|
-
},
|
|
1830
|
-
{
|
|
1831
|
-
"name": "plan-id",
|
|
1832
|
-
"key": "planId"
|
|
1833
|
-
}
|
|
1834
|
-
]
|
|
1896
|
+
"description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
|
|
1835
1897
|
}
|
|
1836
1898
|
],
|
|
1837
1899
|
"example": "ask-marcel-office get-planner-plan --planner-plan-id 'xqQg5FS2LkCp935s-FIFm5gAB6'",
|
|
@@ -1849,17 +1911,7 @@
|
|
|
1849
1911
|
"name": "planner-task-id",
|
|
1850
1912
|
"key": "plannerTaskId",
|
|
1851
1913
|
"required": true,
|
|
1852
|
-
"description": "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`.
|
|
1853
|
-
"aliases": [
|
|
1854
|
-
{
|
|
1855
|
-
"name": "id",
|
|
1856
|
-
"key": "id"
|
|
1857
|
-
},
|
|
1858
|
-
{
|
|
1859
|
-
"name": "task-id",
|
|
1860
|
-
"key": "taskId"
|
|
1861
|
-
}
|
|
1862
|
-
]
|
|
1914
|
+
"description": "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`."
|
|
1863
1915
|
}
|
|
1864
1916
|
],
|
|
1865
1917
|
"example": "ask-marcel-office get-planner-task --planner-task-id '01tx7Ic7-USXEwt0lvR1cmgAH8gK'",
|
|
@@ -1877,17 +1929,7 @@
|
|
|
1877
1929
|
"name": "planner-task-id",
|
|
1878
1930
|
"key": "plannerTaskId",
|
|
1879
1931
|
"required": true,
|
|
1880
|
-
"description": "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`.
|
|
1881
|
-
"aliases": [
|
|
1882
|
-
{
|
|
1883
|
-
"name": "id",
|
|
1884
|
-
"key": "id"
|
|
1885
|
-
},
|
|
1886
|
-
{
|
|
1887
|
-
"name": "task-id",
|
|
1888
|
-
"key": "taskId"
|
|
1889
|
-
}
|
|
1890
|
-
]
|
|
1932
|
+
"description": "Planner task ID. Returned by `ask-marcel-office list-planner-tasks` or `list-plan-tasks`."
|
|
1891
1933
|
}
|
|
1892
1934
|
],
|
|
1893
1935
|
"example": "ask-marcel-office get-planner-task-details --planner-task-id '01tx7Ic7-USXEwt0lvR1cmgAH8gK'",
|
|
@@ -1905,36 +1947,18 @@
|
|
|
1905
1947
|
"name": "schedules",
|
|
1906
1948
|
"key": "schedules",
|
|
1907
1949
|
"required": true,
|
|
1908
|
-
"aliases": [
|
|
1909
|
-
{
|
|
1910
|
-
"name": "emails",
|
|
1911
|
-
"key": "emails"
|
|
1912
|
-
}
|
|
1913
|
-
],
|
|
1914
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`."
|
|
1915
1951
|
},
|
|
1916
1952
|
{
|
|
1917
1953
|
"name": "start-date-time",
|
|
1918
1954
|
"key": "startDateTime",
|
|
1919
1955
|
"required": true,
|
|
1920
|
-
"aliases": [
|
|
1921
|
-
{
|
|
1922
|
-
"name": "start",
|
|
1923
|
-
"key": "start"
|
|
1924
|
-
}
|
|
1925
|
-
],
|
|
1926
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)."
|
|
1927
1957
|
},
|
|
1928
1958
|
{
|
|
1929
1959
|
"name": "end-date-time",
|
|
1930
1960
|
"key": "endDateTime",
|
|
1931
1961
|
"required": true,
|
|
1932
|
-
"aliases": [
|
|
1933
|
-
{
|
|
1934
|
-
"name": "end",
|
|
1935
|
-
"key": "end"
|
|
1936
|
-
}
|
|
1937
|
-
],
|
|
1938
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)."
|
|
1939
1963
|
},
|
|
1940
1964
|
{
|
|
@@ -2041,12 +2065,6 @@
|
|
|
2041
2065
|
"name": "site-id",
|
|
2042
2066
|
"key": "siteId",
|
|
2043
2067
|
"required": true,
|
|
2044
|
-
"aliases": [
|
|
2045
|
-
{
|
|
2046
|
-
"name": "id",
|
|
2047
|
-
"key": "id"
|
|
2048
|
-
}
|
|
2049
|
-
],
|
|
2050
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."
|
|
2051
2069
|
},
|
|
2052
2070
|
{
|
|
@@ -2191,13 +2209,7 @@
|
|
|
2191
2209
|
"name": "list-item-id",
|
|
2192
2210
|
"key": "listItemId",
|
|
2193
2211
|
"required": true,
|
|
2194
|
-
"description": "listItem ID (typically a small integer). Returned by `ask-marcel-office list-sharepoint-site-list-items`."
|
|
2195
|
-
"aliases": [
|
|
2196
|
-
{
|
|
2197
|
-
"name": "item-id",
|
|
2198
|
-
"key": "itemId"
|
|
2199
|
-
}
|
|
2200
|
-
]
|
|
2212
|
+
"description": "listItem ID (typically a small integer). Returned by `ask-marcel-office list-sharepoint-site-list-items`."
|
|
2201
2213
|
},
|
|
2202
2214
|
{
|
|
2203
2215
|
"name": "select",
|
|
@@ -2233,13 +2245,7 @@
|
|
|
2233
2245
|
"name": "onenote-page-id",
|
|
2234
2246
|
"key": "onenotePageId",
|
|
2235
2247
|
"required": true,
|
|
2236
|
-
"description": "OneNote page ID inside the site."
|
|
2237
|
-
"aliases": [
|
|
2238
|
-
{
|
|
2239
|
-
"name": "page-id",
|
|
2240
|
-
"key": "pageId"
|
|
2241
|
-
}
|
|
2242
|
-
]
|
|
2248
|
+
"description": "OneNote page ID inside the site."
|
|
2243
2249
|
}
|
|
2244
2250
|
],
|
|
2245
2251
|
"example": "ask-marcel-office get-sharepoint-site-onenote-page-content --site-id 'contoso.sharepoint.com,...' --onenote-page-id 'p1'",
|
|
@@ -2258,12 +2264,6 @@
|
|
|
2258
2264
|
"name": "site-id",
|
|
2259
2265
|
"key": "siteId",
|
|
2260
2266
|
"required": true,
|
|
2261
|
-
"aliases": [
|
|
2262
|
-
{
|
|
2263
|
-
"name": "id",
|
|
2264
|
-
"key": "id"
|
|
2265
|
-
}
|
|
2266
|
-
],
|
|
2267
2267
|
"description": "SharePoint site ID."
|
|
2268
2268
|
}
|
|
2269
2269
|
],
|
|
@@ -2318,12 +2318,6 @@
|
|
|
2318
2318
|
"name": "team-id",
|
|
2319
2319
|
"key": "teamId",
|
|
2320
2320
|
"required": true,
|
|
2321
|
-
"aliases": [
|
|
2322
|
-
{
|
|
2323
|
-
"name": "id",
|
|
2324
|
-
"key": "id"
|
|
2325
|
-
}
|
|
2326
|
-
],
|
|
2327
2321
|
"description": "Microsoft Teams team ID. Returned by `ask-marcel-office list-joined-teams`."
|
|
2328
2322
|
},
|
|
2329
2323
|
{
|
|
@@ -2390,12 +2384,6 @@
|
|
|
2390
2384
|
"name": "team-id",
|
|
2391
2385
|
"key": "teamId",
|
|
2392
2386
|
"required": true,
|
|
2393
|
-
"aliases": [
|
|
2394
|
-
{
|
|
2395
|
-
"name": "id",
|
|
2396
|
-
"key": "id"
|
|
2397
|
-
}
|
|
2398
|
-
],
|
|
2399
2387
|
"description": "Microsoft Teams team ID. Returned by `list-joined-teams`."
|
|
2400
2388
|
},
|
|
2401
2389
|
{
|
|
@@ -2437,7 +2425,7 @@
|
|
|
2437
2425
|
],
|
|
2438
2426
|
"example": "ask-marcel-office get-teams-chat-message --chat-id '19:abc...@unq.gbl.spaces' --message-id '1700000000000'",
|
|
2439
2427
|
"responseShape": "single Teams chat message — `id`, `from`, `imDisplayName`, `content`, `contentType`, `composeTime`, `originalArrivalTime`, etc. **Microsoft-internal schema — fields may change without notice.**",
|
|
2440
|
-
"needsSubstrateToken":
|
|
2428
|
+
"needsSubstrateToken": "chatsvcagg",
|
|
2441
2429
|
"stability": "experimental"
|
|
2442
2430
|
},
|
|
2443
2431
|
{
|
|
@@ -2452,29 +2440,13 @@
|
|
|
2452
2440
|
"name": "todo-task-list-id",
|
|
2453
2441
|
"key": "todoTaskListId",
|
|
2454
2442
|
"required": true,
|
|
2455
|
-
"description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
|
|
2456
|
-
"aliases": [
|
|
2457
|
-
{
|
|
2458
|
-
"name": "task-list-id",
|
|
2459
|
-
"key": "taskListId"
|
|
2460
|
-
},
|
|
2461
|
-
{
|
|
2462
|
-
"name": "todo-list-id",
|
|
2463
|
-
"key": "todoListId"
|
|
2464
|
-
}
|
|
2465
|
-
]
|
|
2443
|
+
"description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
|
|
2466
2444
|
},
|
|
2467
2445
|
{
|
|
2468
2446
|
"name": "todo-task-id",
|
|
2469
2447
|
"key": "todoTaskId",
|
|
2470
2448
|
"required": true,
|
|
2471
|
-
"description": "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`.
|
|
2472
|
-
"aliases": [
|
|
2473
|
-
{
|
|
2474
|
-
"name": "task-id",
|
|
2475
|
-
"key": "taskId"
|
|
2476
|
-
}
|
|
2477
|
-
]
|
|
2449
|
+
"description": "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`."
|
|
2478
2450
|
},
|
|
2479
2451
|
{
|
|
2480
2452
|
"name": "select",
|
|
@@ -2492,6 +2464,37 @@
|
|
|
2492
2464
|
"example": "ask-marcel-office get-todo-task --todo-task-list-id 'AAMkAGI...' --todo-task-id 'AAMkABC...'",
|
|
2493
2465
|
"responseShape": "single Microsoft Graph `todoTask` resource (slimmed by `--select` when supplied)"
|
|
2494
2466
|
},
|
|
2467
|
+
{
|
|
2468
|
+
"name": "get-user",
|
|
2469
|
+
"summary": "Look up a directory user. Pass an Azure AD id, UPN, or email as --user-id and get that user's FULL profile (displayName, mail, jobTitle, department, officeLocation, phones) via GET /users/{id} on the elevated M365 token — preflight it with `ask-marcel-office scopes-check` (no Graph call) and run `ask-marcel-office login` first if it is cold. An email resolves even when it is the user's `mail` rather than their sign-in UPN: guest / B2B users carry a `#EXT#` UPN whose local part is NOT their email address, so when the direct lookup 404s the command falls back to `GET /users?$filter=mail eq '<email>'` and returns the single match. Only THIS tenant's directory is queried: a person's home-tenant object id (e.g. a cross-tenant Teams `8:orgid:<home-id>` participant, whose id lives in their own tenant) and any email that is not their `mail`/UPN here are unresolvable by design — reach an external person via their LOCAL guest projection (by name, or by their real `mail`), never by their home id. Pass a NAME instead and it searches your relevant-people graph (GET /me/people) and returns candidate matches (id, displayName, mail, jobTitle, department) so you can pick the right person and re-query. Re-query by the candidate's `id` when it is a directory GUID; an EXTERNAL contact's candidate carries a base64-ish People-API id instead, which nothing can resolve — re-query those by the candidate's `mail` (the CLI rejects an opaque contact id with that remedy rather than returning empty matches). Name search covers colleagues in your people graph, not the whole tenant directory; use `microsoft-search-query` for a broader tenant-wide person search. Without `--select`, the profile ships a default projection of id, displayName, userPrincipalName, mail, jobTitle, department, officeLocation, businessPhones, mobilePhone.",
|
|
2470
|
+
"category": "user",
|
|
2471
|
+
"graphMethod": "GET",
|
|
2472
|
+
"graphPathTemplate": "/users/{user-id} (id / UPN; an email that misses falls back to /users?$filter=mail eq) OR /me/people?$search=\"{user-id}\" (a bare name)",
|
|
2473
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/user-get",
|
|
2474
|
+
"options": [
|
|
2475
|
+
{
|
|
2476
|
+
"name": "user-id",
|
|
2477
|
+
"key": "userId",
|
|
2478
|
+
"required": true,
|
|
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`."
|
|
2480
|
+
},
|
|
2481
|
+
{
|
|
2482
|
+
"name": "select",
|
|
2483
|
+
"key": "select",
|
|
2484
|
+
"required": false,
|
|
2485
|
+
"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`."
|
|
2486
|
+
},
|
|
2487
|
+
{
|
|
2488
|
+
"name": "expand",
|
|
2489
|
+
"key": "expand",
|
|
2490
|
+
"required": false,
|
|
2491
|
+
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
2492
|
+
}
|
|
2493
|
+
],
|
|
2494
|
+
"example": "ask-marcel-office get-user --user-id 'alice@contoso.com' --select 'id,displayName,mail,jobTitle,department'",
|
|
2495
|
+
"responseShape": "For an id / UPN / email: a single Microsoft Graph `user` resource projected to the default `$select` (id, displayName, userPrincipalName, mail, jobTitle, department, officeLocation, businessPhones, mobilePhone) unless `--select` overrides it; honours `--expand`. An email is tried against the sign-in UPN first, then falls back to the `mail` attribute (`$filter=mail eq`) so guest/B2B users resolve; an email that matches nobody returns the direct-path 404. For a name: `{ query, matches: [{ id, displayName, mail, jobTitle, department }] }` from the People API (empty `matches` when nobody in your relevant-people graph matches; re-query by a chosen GUID `id`, or by `mail` when the candidate is an external contact with a base64-ish People-API id — passing that id back is rejected with the same remedy). The id path needs the elevated M365 token and fail-fasts with `secondary_token_unavailable` when it is cold — preflight with `ask-marcel-office scopes-check` and run `ask-marcel-office login` to re-capture it.",
|
|
2496
|
+
"needsElevatedToken": true
|
|
2497
|
+
},
|
|
2495
2498
|
{
|
|
2496
2499
|
"name": "get-user-manager",
|
|
2497
2500
|
"summary": "Return a specific user's manager (a single `user` resource). When the user has no manager set in the directory, Graph returns 404 `Request_ResourceNotFound`; this command maps that one specific 404 to `{ ok: true, data: { manager: null, note: '...' } }` (same shape as `get-my-manager`) so an LLM can distinguish 'no manager' from 'unknown user' with a single discriminator across both commands. Use `--select` to slim the response.",
|
|
@@ -2504,12 +2507,6 @@
|
|
|
2504
2507
|
"name": "user-id",
|
|
2505
2508
|
"key": "userId",
|
|
2506
2509
|
"required": true,
|
|
2507
|
-
"aliases": [
|
|
2508
|
-
{
|
|
2509
|
-
"name": "id",
|
|
2510
|
-
"key": "id"
|
|
2511
|
-
}
|
|
2512
|
-
],
|
|
2513
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)."
|
|
2514
2511
|
},
|
|
2515
2512
|
{
|
|
@@ -2619,12 +2616,6 @@
|
|
|
2619
2616
|
"name": "event-id",
|
|
2620
2617
|
"key": "eventId",
|
|
2621
2618
|
"required": true,
|
|
2622
|
-
"aliases": [
|
|
2623
|
-
{
|
|
2624
|
-
"name": "id",
|
|
2625
|
-
"key": "id"
|
|
2626
|
-
}
|
|
2627
|
-
],
|
|
2628
2619
|
"description": "Outlook calendar event ID. Returned by `ask-marcel-office list-calendar-events` or `get-calendar-event`."
|
|
2629
2620
|
},
|
|
2630
2621
|
{
|
|
@@ -2693,36 +2684,18 @@
|
|
|
2693
2684
|
"name": "event-id",
|
|
2694
2685
|
"key": "eventId",
|
|
2695
2686
|
"required": true,
|
|
2696
|
-
"aliases": [
|
|
2697
|
-
{
|
|
2698
|
-
"name": "id",
|
|
2699
|
-
"key": "id"
|
|
2700
|
-
}
|
|
2701
|
-
],
|
|
2702
2687
|
"description": "Recurring event ID. Returned by `ask-marcel-office list-specific-calendar-events`."
|
|
2703
2688
|
},
|
|
2704
2689
|
{
|
|
2705
2690
|
"name": "start-date-time",
|
|
2706
2691
|
"key": "startDateTime",
|
|
2707
2692
|
"required": true,
|
|
2708
|
-
"aliases": [
|
|
2709
|
-
{
|
|
2710
|
-
"name": "start",
|
|
2711
|
-
"key": "start"
|
|
2712
|
-
}
|
|
2713
|
-
],
|
|
2714
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)."
|
|
2715
2694
|
},
|
|
2716
2695
|
{
|
|
2717
2696
|
"name": "end-date-time",
|
|
2718
2697
|
"key": "endDateTime",
|
|
2719
2698
|
"required": true,
|
|
2720
|
-
"aliases": [
|
|
2721
|
-
{
|
|
2722
|
-
"name": "end",
|
|
2723
|
-
"key": "end"
|
|
2724
|
-
}
|
|
2725
|
-
],
|
|
2726
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)."
|
|
2727
2700
|
},
|
|
2728
2701
|
{
|
|
@@ -2846,12 +2819,6 @@
|
|
|
2846
2819
|
"name": "calendar-group-id",
|
|
2847
2820
|
"key": "calendarGroupId",
|
|
2848
2821
|
"required": true,
|
|
2849
|
-
"aliases": [
|
|
2850
|
-
{
|
|
2851
|
-
"name": "id",
|
|
2852
|
-
"key": "id"
|
|
2853
|
-
}
|
|
2854
|
-
],
|
|
2855
2822
|
"description": "Calendar group ID. Returned by `list-calendar-groups`."
|
|
2856
2823
|
},
|
|
2857
2824
|
{
|
|
@@ -2956,24 +2923,12 @@
|
|
|
2956
2923
|
"name": "start-date-time",
|
|
2957
2924
|
"key": "startDateTime",
|
|
2958
2925
|
"required": true,
|
|
2959
|
-
"aliases": [
|
|
2960
|
-
{
|
|
2961
|
-
"name": "start",
|
|
2962
|
-
"key": "start"
|
|
2963
|
-
}
|
|
2964
|
-
],
|
|
2965
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)."
|
|
2966
2927
|
},
|
|
2967
2928
|
{
|
|
2968
2929
|
"name": "end-date-time",
|
|
2969
2930
|
"key": "endDateTime",
|
|
2970
2931
|
"required": true,
|
|
2971
|
-
"aliases": [
|
|
2972
|
-
{
|
|
2973
|
-
"name": "end",
|
|
2974
|
-
"key": "end"
|
|
2975
|
-
}
|
|
2976
|
-
],
|
|
2977
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)."
|
|
2978
2933
|
},
|
|
2979
2934
|
{
|
|
@@ -3028,24 +2983,12 @@
|
|
|
3028
2983
|
"name": "start-date-time",
|
|
3029
2984
|
"key": "startDateTime",
|
|
3030
2985
|
"required": true,
|
|
3031
|
-
"aliases": [
|
|
3032
|
-
{
|
|
3033
|
-
"name": "start",
|
|
3034
|
-
"key": "start"
|
|
3035
|
-
}
|
|
3036
|
-
],
|
|
3037
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)."
|
|
3038
2987
|
},
|
|
3039
2988
|
{
|
|
3040
2989
|
"name": "end-date-time",
|
|
3041
2990
|
"key": "endDateTime",
|
|
3042
2991
|
"required": true,
|
|
3043
|
-
"aliases": [
|
|
3044
|
-
{
|
|
3045
|
-
"name": "end",
|
|
3046
|
-
"key": "end"
|
|
3047
|
-
}
|
|
3048
|
-
],
|
|
3049
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)."
|
|
3050
2993
|
},
|
|
3051
2994
|
{
|
|
@@ -3120,12 +3063,6 @@
|
|
|
3120
3063
|
"name": "chat-id",
|
|
3121
3064
|
"key": "chatId",
|
|
3122
3065
|
"required": true,
|
|
3123
|
-
"aliases": [
|
|
3124
|
-
{
|
|
3125
|
-
"name": "id",
|
|
3126
|
-
"key": "id"
|
|
3127
|
-
}
|
|
3128
|
-
],
|
|
3129
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`."
|
|
3130
3067
|
},
|
|
3131
3068
|
{
|
|
@@ -3201,12 +3138,6 @@
|
|
|
3201
3138
|
"name": "conversation-id",
|
|
3202
3139
|
"key": "conversationId",
|
|
3203
3140
|
"required": true,
|
|
3204
|
-
"aliases": [
|
|
3205
|
-
{
|
|
3206
|
-
"name": "id",
|
|
3207
|
-
"key": "id"
|
|
3208
|
-
}
|
|
3209
|
-
],
|
|
3210
3141
|
"description": "Outlook `conversationId` of any message in the thread (returned by every mail-listing command and by `get-mail-message`)."
|
|
3211
3142
|
},
|
|
3212
3143
|
{
|
|
@@ -3287,6 +3218,12 @@
|
|
|
3287
3218
|
"key": "expand",
|
|
3288
3219
|
"required": false,
|
|
3289
3220
|
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
3221
|
+
},
|
|
3222
|
+
{
|
|
3223
|
+
"name": "tenant-id",
|
|
3224
|
+
"key": "tenantId",
|
|
3225
|
+
"required": false,
|
|
3226
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
3290
3227
|
}
|
|
3291
3228
|
],
|
|
3292
3229
|
"example": "ask-marcel-office list-drive-item-permissions --drive-id 'b!1234' --item-id '01ABC'",
|
|
@@ -3342,6 +3279,12 @@
|
|
|
3342
3279
|
"key": "expand",
|
|
3343
3280
|
"required": false,
|
|
3344
3281
|
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
3282
|
+
},
|
|
3283
|
+
{
|
|
3284
|
+
"name": "tenant-id",
|
|
3285
|
+
"key": "tenantId",
|
|
3286
|
+
"required": false,
|
|
3287
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
3345
3288
|
}
|
|
3346
3289
|
],
|
|
3347
3290
|
"example": "ask-marcel-office list-drive-item-thumbnails --drive-id 'b!1234' --item-id '01ABC'",
|
|
@@ -3397,6 +3340,12 @@
|
|
|
3397
3340
|
"key": "expand",
|
|
3398
3341
|
"required": false,
|
|
3399
3342
|
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
3343
|
+
},
|
|
3344
|
+
{
|
|
3345
|
+
"name": "tenant-id",
|
|
3346
|
+
"key": "tenantId",
|
|
3347
|
+
"required": false,
|
|
3348
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
3400
3349
|
}
|
|
3401
3350
|
],
|
|
3402
3351
|
"example": "ask-marcel-office list-drive-item-versions --drive-id 'b!1234' --item-id '01ABC'",
|
|
@@ -3928,13 +3877,7 @@
|
|
|
3928
3877
|
"name": "item-id",
|
|
3929
3878
|
"key": "itemId",
|
|
3930
3879
|
"required": true,
|
|
3931
|
-
"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.
|
|
3932
|
-
"aliases": [
|
|
3933
|
-
{
|
|
3934
|
-
"name": "folder-id",
|
|
3935
|
-
"key": "folderId"
|
|
3936
|
-
}
|
|
3937
|
-
]
|
|
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."
|
|
3938
3881
|
},
|
|
3939
3882
|
{
|
|
3940
3883
|
"name": "top",
|
|
@@ -3965,6 +3908,12 @@
|
|
|
3965
3908
|
"key": "expand",
|
|
3966
3909
|
"required": false,
|
|
3967
3910
|
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
3911
|
+
},
|
|
3912
|
+
{
|
|
3913
|
+
"name": "tenant-id",
|
|
3914
|
+
"key": "tenantId",
|
|
3915
|
+
"required": false,
|
|
3916
|
+
"description": "Tenant GUID of a PARTNER tenant you are a guest in, when the file does not live in your own tenant. Get it from `resolve-drive-share-link`, which returns `tenantId` on any sharing URL whose file belongs to another tenant — that is the only place the tenant is knowable, because `--drive-id` and `--item-id` carry no tenant at all. Omit it for files in your own tenant (the normal case). Pass it and the request is signed with a guest token minted for that tenant instead of your home token; without it, a partner-tenant file fails with `invalidAudienceUri` no matter which of your tokens is used."
|
|
3968
3917
|
}
|
|
3969
3918
|
],
|
|
3970
3919
|
"example": "ask-marcel-office list-folder-files --drive-id 'b!1234' --item-id '01ROOT'",
|
|
@@ -4026,36 +3975,18 @@
|
|
|
4026
3975
|
"name": "group-id",
|
|
4027
3976
|
"key": "groupId",
|
|
4028
3977
|
"required": true,
|
|
4029
|
-
"aliases": [
|
|
4030
|
-
{
|
|
4031
|
-
"name": "id",
|
|
4032
|
-
"key": "id"
|
|
4033
|
-
}
|
|
4034
|
-
],
|
|
4035
3978
|
"description": "Azure AD group object ID for a unified (Microsoft 365) group."
|
|
4036
3979
|
},
|
|
4037
3980
|
{
|
|
4038
3981
|
"name": "start-date-time",
|
|
4039
3982
|
"key": "startDateTime",
|
|
4040
3983
|
"required": true,
|
|
4041
|
-
"aliases": [
|
|
4042
|
-
{
|
|
4043
|
-
"name": "start",
|
|
4044
|
-
"key": "start"
|
|
4045
|
-
}
|
|
4046
|
-
],
|
|
4047
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)."
|
|
4048
3985
|
},
|
|
4049
3986
|
{
|
|
4050
3987
|
"name": "end-date-time",
|
|
4051
3988
|
"key": "endDateTime",
|
|
4052
3989
|
"required": true,
|
|
4053
|
-
"aliases": [
|
|
4054
|
-
{
|
|
4055
|
-
"name": "end",
|
|
4056
|
-
"key": "end"
|
|
4057
|
-
}
|
|
4058
|
-
],
|
|
4059
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)."
|
|
4060
3991
|
},
|
|
4061
3992
|
{
|
|
@@ -4111,12 +4042,6 @@
|
|
|
4111
4042
|
"name": "group-id",
|
|
4112
4043
|
"key": "groupId",
|
|
4113
4044
|
"required": true,
|
|
4114
|
-
"aliases": [
|
|
4115
|
-
{
|
|
4116
|
-
"name": "id",
|
|
4117
|
-
"key": "id"
|
|
4118
|
-
}
|
|
4119
|
-
],
|
|
4120
4045
|
"description": "Azure AD group object ID for a unified (Microsoft 365) group."
|
|
4121
4046
|
},
|
|
4122
4047
|
{
|
|
@@ -4172,12 +4097,6 @@
|
|
|
4172
4097
|
"name": "group-id",
|
|
4173
4098
|
"key": "groupId",
|
|
4174
4099
|
"required": true,
|
|
4175
|
-
"aliases": [
|
|
4176
|
-
{
|
|
4177
|
-
"name": "id",
|
|
4178
|
-
"key": "id"
|
|
4179
|
-
}
|
|
4180
|
-
],
|
|
4181
4100
|
"description": "Azure AD group object ID for a unified (Microsoft 365) group. Use `list-groups` to find one."
|
|
4182
4101
|
},
|
|
4183
4102
|
{
|
|
@@ -4233,12 +4152,6 @@
|
|
|
4233
4152
|
"name": "group-id",
|
|
4234
4153
|
"key": "groupId",
|
|
4235
4154
|
"required": true,
|
|
4236
|
-
"aliases": [
|
|
4237
|
-
{
|
|
4238
|
-
"name": "id",
|
|
4239
|
-
"key": "id"
|
|
4240
|
-
}
|
|
4241
|
-
],
|
|
4242
4155
|
"description": "Azure AD group object ID. Use `list-groups` to find one."
|
|
4243
4156
|
},
|
|
4244
4157
|
{
|
|
@@ -4294,12 +4207,6 @@
|
|
|
4294
4207
|
"name": "group-id",
|
|
4295
4208
|
"key": "groupId",
|
|
4296
4209
|
"required": true,
|
|
4297
|
-
"aliases": [
|
|
4298
|
-
{
|
|
4299
|
-
"name": "id",
|
|
4300
|
-
"key": "id"
|
|
4301
|
-
}
|
|
4302
|
-
],
|
|
4303
4210
|
"description": "Azure AD group object ID. Use `list-groups` to find one."
|
|
4304
4211
|
},
|
|
4305
4212
|
{
|
|
@@ -4355,12 +4262,6 @@
|
|
|
4355
4262
|
"name": "group-id",
|
|
4356
4263
|
"key": "groupId",
|
|
4357
4264
|
"required": true,
|
|
4358
|
-
"aliases": [
|
|
4359
|
-
{
|
|
4360
|
-
"name": "id",
|
|
4361
|
-
"key": "id"
|
|
4362
|
-
}
|
|
4363
|
-
],
|
|
4364
4265
|
"description": "Azure AD group object ID for a unified (Microsoft 365) group."
|
|
4365
4266
|
},
|
|
4366
4267
|
{
|
|
@@ -4508,21 +4409,7 @@
|
|
|
4508
4409
|
"name": "todo-task-list-id",
|
|
4509
4410
|
"key": "todoTaskListId",
|
|
4510
4411
|
"required": true,
|
|
4511
|
-
"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."
|
|
4512
|
-
"aliases": [
|
|
4513
|
-
{
|
|
4514
|
-
"name": "id",
|
|
4515
|
-
"key": "id"
|
|
4516
|
-
},
|
|
4517
|
-
{
|
|
4518
|
-
"name": "task-list-id",
|
|
4519
|
-
"key": "taskListId"
|
|
4520
|
-
},
|
|
4521
|
-
{
|
|
4522
|
-
"name": "todo-list-id",
|
|
4523
|
-
"key": "todoListId"
|
|
4524
|
-
}
|
|
4525
|
-
]
|
|
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."
|
|
4526
4413
|
},
|
|
4527
4414
|
{
|
|
4528
4415
|
"name": "top",
|
|
@@ -4589,13 +4476,7 @@
|
|
|
4589
4476
|
"name": "message-id",
|
|
4590
4477
|
"key": "messageId",
|
|
4591
4478
|
"required": true,
|
|
4592
|
-
"
|
|
4593
|
-
{
|
|
4594
|
-
"name": "id",
|
|
4595
|
-
"key": "id"
|
|
4596
|
-
}
|
|
4597
|
-
],
|
|
4598
|
-
"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`."
|
|
4599
4480
|
},
|
|
4600
4481
|
{
|
|
4601
4482
|
"name": "top",
|
|
@@ -4650,12 +4531,6 @@
|
|
|
4650
4531
|
"name": "mail-folder-id",
|
|
4651
4532
|
"key": "mailFolderId",
|
|
4652
4533
|
"required": true,
|
|
4653
|
-
"aliases": [
|
|
4654
|
-
{
|
|
4655
|
-
"name": "id",
|
|
4656
|
-
"key": "id"
|
|
4657
|
-
}
|
|
4658
|
-
],
|
|
4659
4534
|
"description": "mailFolder ID. Returned by `ask-marcel-office list-mail-folders`. Well-known names also work, e.g. `inbox`, `sentitems`, `drafts`."
|
|
4660
4535
|
},
|
|
4661
4536
|
{
|
|
@@ -4711,13 +4586,7 @@
|
|
|
4711
4586
|
"name": "mail-folder-id",
|
|
4712
4587
|
"key": "mailFolderId",
|
|
4713
4588
|
"required": true,
|
|
4714
|
-
"
|
|
4715
|
-
{
|
|
4716
|
-
"name": "id",
|
|
4717
|
-
"key": "id"
|
|
4718
|
-
}
|
|
4719
|
-
],
|
|
4720
|
-
"description": "mailFolder ID. Returned by `ask-marcel-office list-mail-folders`. Well-known names also work, e.g. `inbox`, `sentitems`, `drafts`."
|
|
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."
|
|
4721
4590
|
},
|
|
4722
4591
|
{
|
|
4723
4592
|
"name": "top",
|
|
@@ -4762,7 +4631,7 @@
|
|
|
4762
4631
|
},
|
|
4763
4632
|
{
|
|
4764
4633
|
"name": "list-mail-folder-messages-delta",
|
|
4765
|
-
"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`.",
|
|
4766
4635
|
"category": "mail",
|
|
4767
4636
|
"graphMethod": "GET",
|
|
4768
4637
|
"graphPathTemplate": "/me/mailFolders/{mail-folder-id}/messages/delta()",
|
|
@@ -4772,12 +4641,6 @@
|
|
|
4772
4641
|
"name": "mail-folder-id",
|
|
4773
4642
|
"key": "mailFolderId",
|
|
4774
4643
|
"required": true,
|
|
4775
|
-
"aliases": [
|
|
4776
|
-
{
|
|
4777
|
-
"name": "id",
|
|
4778
|
-
"key": "id"
|
|
4779
|
-
}
|
|
4780
|
-
],
|
|
4781
4644
|
"description": "Mail folder ID or well-known name (`inbox`, `archive`, `sentitems`, `deleteditems`, `junkemail`, `drafts`). Returned by `list-mail-folders`."
|
|
4782
4645
|
},
|
|
4783
4646
|
{
|
|
@@ -4786,12 +4649,6 @@
|
|
|
4786
4649
|
"required": false,
|
|
4787
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."
|
|
4788
4651
|
},
|
|
4789
|
-
{
|
|
4790
|
-
"name": "skip",
|
|
4791
|
-
"key": "skip",
|
|
4792
|
-
"required": false,
|
|
4793
|
-
"description": "OData $skip: skip the first N items before returning results (non-negative integer). Useful with $top for offset paging."
|
|
4794
|
-
},
|
|
4795
4652
|
{
|
|
4796
4653
|
"name": "select",
|
|
4797
4654
|
"key": "select",
|
|
@@ -4804,12 +4661,6 @@
|
|
|
4804
4661
|
"required": false,
|
|
4805
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."
|
|
4806
4663
|
},
|
|
4807
|
-
{
|
|
4808
|
-
"name": "orderby",
|
|
4809
|
-
"key": "orderby",
|
|
4810
|
-
"required": false,
|
|
4811
|
-
"description": "OData $orderby: sort expression with optional asc/desc (e.g. `receivedDateTime desc`). Some Graph filter combinations are rejected; remove $orderby if InefficientFilter occurs."
|
|
4812
|
-
},
|
|
4813
4664
|
{
|
|
4814
4665
|
"name": "expand",
|
|
4815
4666
|
"key": "expand",
|
|
@@ -4818,7 +4669,7 @@
|
|
|
4818
4669
|
}
|
|
4819
4670
|
],
|
|
4820
4671
|
"example": "ask-marcel-office list-mail-folder-messages-delta --mail-folder-id 'inbox'",
|
|
4821
|
-
"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.",
|
|
4822
4673
|
"pagination": true
|
|
4823
4674
|
},
|
|
4824
4675
|
{
|
|
@@ -4884,7 +4735,7 @@
|
|
|
4884
4735
|
},
|
|
4885
4736
|
{
|
|
4886
4737
|
"name": "list-mail-messages",
|
|
4887
|
-
"summary": "List the most recent messages from across the signed-in user's entire Outlook mailbox (every folder including Sent, Archive, Junk; default sort `receivedDateTime` desc). The CLI ships a slim default `--select=id,subject,from,toRecipients,ccRecipients,receivedDateTime,hasAttachments,isRead,importance,bodyPreview` so a page of 25 messages stays ~30-60 KB instead of ~1 MB. Pass `--select id,subject,body` (or any other comma-separated field list) to override. Use `list-mail-folder-messages` to scope to a single folder such as Inbox.",
|
|
4738
|
+
"summary": "List the most recent messages from across the signed-in user's entire Outlook mailbox (every folder including Sent, Archive, Junk; default sort `receivedDateTime` desc). The CLI ships a slim default `--select=id,subject,from,toRecipients,ccRecipients,receivedDateTime,hasAttachments,isRead,importance,bodyPreview,conversationId` (`conversationId` groups messages into a thread and can be handed to `list-conversation-messages`) so a page of 25 messages stays ~30-60 KB instead of ~1 MB. Pass `--select id,subject,body` (or any other comma-separated field list) to override. Use `list-mail-folder-messages` to scope to a single folder such as Inbox.",
|
|
4888
4739
|
"category": "mail",
|
|
4889
4740
|
"graphMethod": "GET",
|
|
4890
4741
|
"graphPathTemplate": "/me/messages",
|
|
@@ -5108,12 +4959,6 @@
|
|
|
5108
4959
|
"name": "notebook-id",
|
|
5109
4960
|
"key": "notebookId",
|
|
5110
4961
|
"required": true,
|
|
5111
|
-
"aliases": [
|
|
5112
|
-
{
|
|
5113
|
-
"name": "id",
|
|
5114
|
-
"key": "id"
|
|
5115
|
-
}
|
|
5116
|
-
],
|
|
5117
4962
|
"description": "OneNote notebook ID. Returned by `ask-marcel-office list-onenote-notebooks`."
|
|
5118
4963
|
},
|
|
5119
4964
|
{
|
|
@@ -5218,17 +5063,7 @@
|
|
|
5218
5063
|
"name": "onenote-section-id",
|
|
5219
5064
|
"key": "onenoteSectionId",
|
|
5220
5065
|
"required": true,
|
|
5221
|
-
"description": "OneNote section ID. Returned by `ask-marcel-office list-onenote-notebook-sections` or `list-all-onenote-sections`."
|
|
5222
|
-
"aliases": [
|
|
5223
|
-
{
|
|
5224
|
-
"name": "id",
|
|
5225
|
-
"key": "id"
|
|
5226
|
-
},
|
|
5227
|
-
{
|
|
5228
|
-
"name": "section-id",
|
|
5229
|
-
"key": "sectionId"
|
|
5230
|
-
}
|
|
5231
|
-
]
|
|
5066
|
+
"description": "OneNote section ID. Returned by `ask-marcel-office list-onenote-notebook-sections` or `list-all-onenote-sections`."
|
|
5232
5067
|
},
|
|
5233
5068
|
{
|
|
5234
5069
|
"name": "top",
|
|
@@ -5294,17 +5129,7 @@
|
|
|
5294
5129
|
"name": "planner-plan-id",
|
|
5295
5130
|
"key": "plannerPlanId",
|
|
5296
5131
|
"required": true,
|
|
5297
|
-
"description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
|
|
5298
|
-
"aliases": [
|
|
5299
|
-
{
|
|
5300
|
-
"name": "id",
|
|
5301
|
-
"key": "id"
|
|
5302
|
-
},
|
|
5303
|
-
{
|
|
5304
|
-
"name": "plan-id",
|
|
5305
|
-
"key": "planId"
|
|
5306
|
-
}
|
|
5307
|
-
]
|
|
5132
|
+
"description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
|
|
5308
5133
|
},
|
|
5309
5134
|
{
|
|
5310
5135
|
"name": "select",
|
|
@@ -5329,17 +5154,7 @@
|
|
|
5329
5154
|
"name": "planner-plan-id",
|
|
5330
5155
|
"key": "plannerPlanId",
|
|
5331
5156
|
"required": true,
|
|
5332
|
-
"description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
|
|
5333
|
-
"aliases": [
|
|
5334
|
-
{
|
|
5335
|
-
"name": "id",
|
|
5336
|
-
"key": "id"
|
|
5337
|
-
},
|
|
5338
|
-
{
|
|
5339
|
-
"name": "plan-id",
|
|
5340
|
-
"key": "planId"
|
|
5341
|
-
}
|
|
5342
|
-
]
|
|
5157
|
+
"description": "Planner plan ID. Returned in the `planId` field of any task from `ask-marcel-office list-planner-tasks`."
|
|
5343
5158
|
}
|
|
5344
5159
|
],
|
|
5345
5160
|
"example": "ask-marcel-office list-plan-tasks --planner-plan-id 'xqQg5FS2LkCp935s-FIFm5gAB6'",
|
|
@@ -5714,12 +5529,6 @@
|
|
|
5714
5529
|
"name": "user-id",
|
|
5715
5530
|
"key": "userId",
|
|
5716
5531
|
"required": true,
|
|
5717
|
-
"aliases": [
|
|
5718
|
-
{
|
|
5719
|
-
"name": "id",
|
|
5720
|
-
"key": "id"
|
|
5721
|
-
}
|
|
5722
|
-
],
|
|
5723
5532
|
"description": "Azure AD user ID or UPN whose calendar to read. Requires `Calendars.Read.Shared` access (granted by the calendar owner)."
|
|
5724
5533
|
},
|
|
5725
5534
|
{
|
|
@@ -5775,36 +5584,18 @@
|
|
|
5775
5584
|
"name": "user-id",
|
|
5776
5585
|
"key": "userId",
|
|
5777
5586
|
"required": true,
|
|
5778
|
-
"aliases": [
|
|
5779
|
-
{
|
|
5780
|
-
"name": "id",
|
|
5781
|
-
"key": "id"
|
|
5782
|
-
}
|
|
5783
|
-
],
|
|
5784
5587
|
"description": "Azure AD user ID or UPN of the calendar owner."
|
|
5785
5588
|
},
|
|
5786
5589
|
{
|
|
5787
5590
|
"name": "start-date-time",
|
|
5788
5591
|
"key": "startDateTime",
|
|
5789
5592
|
"required": true,
|
|
5790
|
-
"aliases": [
|
|
5791
|
-
{
|
|
5792
|
-
"name": "start",
|
|
5793
|
-
"key": "start"
|
|
5794
|
-
}
|
|
5795
|
-
],
|
|
5796
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)."
|
|
5797
5594
|
},
|
|
5798
5595
|
{
|
|
5799
5596
|
"name": "end-date-time",
|
|
5800
5597
|
"key": "endDateTime",
|
|
5801
5598
|
"required": true,
|
|
5802
|
-
"aliases": [
|
|
5803
|
-
{
|
|
5804
|
-
"name": "end",
|
|
5805
|
-
"key": "end"
|
|
5806
|
-
}
|
|
5807
|
-
],
|
|
5808
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)."
|
|
5809
5600
|
},
|
|
5810
5601
|
{
|
|
@@ -5970,12 +5761,6 @@
|
|
|
5970
5761
|
"name": "user-id",
|
|
5971
5762
|
"key": "userId",
|
|
5972
5763
|
"required": true,
|
|
5973
|
-
"aliases": [
|
|
5974
|
-
{
|
|
5975
|
-
"name": "id",
|
|
5976
|
-
"key": "id"
|
|
5977
|
-
}
|
|
5978
|
-
],
|
|
5979
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)."
|
|
5980
5765
|
},
|
|
5981
5766
|
{
|
|
@@ -6090,13 +5875,7 @@
|
|
|
6090
5875
|
"name": "list-item-id",
|
|
6091
5876
|
"key": "listItemId",
|
|
6092
5877
|
"required": true,
|
|
6093
|
-
"description": "List item ID inside the list. Returned by `list-sharepoint-site-list-items`."
|
|
6094
|
-
"aliases": [
|
|
6095
|
-
{
|
|
6096
|
-
"name": "item-id",
|
|
6097
|
-
"key": "itemId"
|
|
6098
|
-
}
|
|
6099
|
-
]
|
|
5878
|
+
"description": "List item ID inside the list. Returned by `list-sharepoint-site-list-items`."
|
|
6100
5879
|
},
|
|
6101
5880
|
{
|
|
6102
5881
|
"name": "top",
|
|
@@ -6145,12 +5924,6 @@
|
|
|
6145
5924
|
"name": "site-id",
|
|
6146
5925
|
"key": "siteId",
|
|
6147
5926
|
"required": true,
|
|
6148
|
-
"aliases": [
|
|
6149
|
-
{
|
|
6150
|
-
"name": "id",
|
|
6151
|
-
"key": "id"
|
|
6152
|
-
}
|
|
6153
|
-
],
|
|
6154
5927
|
"description": "SharePoint site ID. Returned by `ask-marcel-office search-sharepoint-sites-by-name`."
|
|
6155
5928
|
},
|
|
6156
5929
|
{
|
|
@@ -6258,12 +6031,6 @@
|
|
|
6258
6031
|
"name": "site-id",
|
|
6259
6032
|
"key": "siteId",
|
|
6260
6033
|
"required": true,
|
|
6261
|
-
"aliases": [
|
|
6262
|
-
{
|
|
6263
|
-
"name": "id",
|
|
6264
|
-
"key": "id"
|
|
6265
|
-
}
|
|
6266
|
-
],
|
|
6267
6034
|
"description": "SharePoint site ID. Returned by `ask-marcel-office search-sharepoint-sites-by-name`."
|
|
6268
6035
|
},
|
|
6269
6036
|
{
|
|
@@ -6374,12 +6141,6 @@
|
|
|
6374
6141
|
"name": "site-id",
|
|
6375
6142
|
"key": "siteId",
|
|
6376
6143
|
"required": true,
|
|
6377
|
-
"aliases": [
|
|
6378
|
-
{
|
|
6379
|
-
"name": "id",
|
|
6380
|
-
"key": "id"
|
|
6381
|
-
}
|
|
6382
|
-
],
|
|
6383
6144
|
"description": "SharePoint site ID."
|
|
6384
6145
|
},
|
|
6385
6146
|
{
|
|
@@ -6441,13 +6202,7 @@
|
|
|
6441
6202
|
"name": "onenote-section-id",
|
|
6442
6203
|
"key": "onenoteSectionId",
|
|
6443
6204
|
"required": true,
|
|
6444
|
-
"description": "OneNote section ID inside the site."
|
|
6445
|
-
"aliases": [
|
|
6446
|
-
{
|
|
6447
|
-
"name": "section-id",
|
|
6448
|
-
"key": "sectionId"
|
|
6449
|
-
}
|
|
6450
|
-
]
|
|
6205
|
+
"description": "OneNote section ID inside the site."
|
|
6451
6206
|
},
|
|
6452
6207
|
{
|
|
6453
6208
|
"name": "top",
|
|
@@ -6502,12 +6257,6 @@
|
|
|
6502
6257
|
"name": "site-id",
|
|
6503
6258
|
"key": "siteId",
|
|
6504
6259
|
"required": true,
|
|
6505
|
-
"aliases": [
|
|
6506
|
-
{
|
|
6507
|
-
"name": "id",
|
|
6508
|
-
"key": "id"
|
|
6509
|
-
}
|
|
6510
|
-
],
|
|
6511
6260
|
"description": "SharePoint site ID."
|
|
6512
6261
|
},
|
|
6513
6262
|
{
|
|
@@ -6557,12 +6306,6 @@
|
|
|
6557
6306
|
"name": "site-id",
|
|
6558
6307
|
"key": "siteId",
|
|
6559
6308
|
"required": true,
|
|
6560
|
-
"aliases": [
|
|
6561
|
-
{
|
|
6562
|
-
"name": "id",
|
|
6563
|
-
"key": "id"
|
|
6564
|
-
}
|
|
6565
|
-
],
|
|
6566
6309
|
"description": "SharePoint site ID. Returned by `search-sharepoint-sites-by-name`."
|
|
6567
6310
|
},
|
|
6568
6311
|
{
|
|
@@ -6593,12 +6336,6 @@
|
|
|
6593
6336
|
"name": "site-id",
|
|
6594
6337
|
"key": "siteId",
|
|
6595
6338
|
"required": true,
|
|
6596
|
-
"aliases": [
|
|
6597
|
-
{
|
|
6598
|
-
"name": "id",
|
|
6599
|
-
"key": "id"
|
|
6600
|
-
}
|
|
6601
|
-
],
|
|
6602
6339
|
"description": "SharePoint site ID."
|
|
6603
6340
|
},
|
|
6604
6341
|
{
|
|
@@ -6648,12 +6385,6 @@
|
|
|
6648
6385
|
"name": "calendar-id",
|
|
6649
6386
|
"key": "calendarId",
|
|
6650
6387
|
"required": true,
|
|
6651
|
-
"aliases": [
|
|
6652
|
-
{
|
|
6653
|
-
"name": "id",
|
|
6654
|
-
"key": "id"
|
|
6655
|
-
}
|
|
6656
|
-
],
|
|
6657
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."
|
|
6658
6389
|
},
|
|
6659
6390
|
{
|
|
@@ -6709,36 +6440,18 @@
|
|
|
6709
6440
|
"name": "calendar-id",
|
|
6710
6441
|
"key": "calendarId",
|
|
6711
6442
|
"required": true,
|
|
6712
|
-
"aliases": [
|
|
6713
|
-
{
|
|
6714
|
-
"name": "id",
|
|
6715
|
-
"key": "id"
|
|
6716
|
-
}
|
|
6717
|
-
],
|
|
6718
6443
|
"description": "Calendar ID, or `primary` / `default` for the signed-in user’s default calendar. Returned by `ask-marcel-office list-calendars`."
|
|
6719
6444
|
},
|
|
6720
6445
|
{
|
|
6721
6446
|
"name": "start-date-time",
|
|
6722
6447
|
"key": "startDateTime",
|
|
6723
6448
|
"required": true,
|
|
6724
|
-
"aliases": [
|
|
6725
|
-
{
|
|
6726
|
-
"name": "start",
|
|
6727
|
-
"key": "start"
|
|
6728
|
-
}
|
|
6729
|
-
],
|
|
6730
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)."
|
|
6731
6450
|
},
|
|
6732
6451
|
{
|
|
6733
6452
|
"name": "end-date-time",
|
|
6734
6453
|
"key": "endDateTime",
|
|
6735
6454
|
"required": true,
|
|
6736
|
-
"aliases": [
|
|
6737
|
-
{
|
|
6738
|
-
"name": "end",
|
|
6739
|
-
"key": "end"
|
|
6740
|
-
}
|
|
6741
|
-
],
|
|
6742
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)."
|
|
6743
6456
|
},
|
|
6744
6457
|
{
|
|
@@ -6793,12 +6506,6 @@
|
|
|
6793
6506
|
"name": "team-id",
|
|
6794
6507
|
"key": "teamId",
|
|
6795
6508
|
"required": true,
|
|
6796
|
-
"aliases": [
|
|
6797
|
-
{
|
|
6798
|
-
"name": "id",
|
|
6799
|
-
"key": "id"
|
|
6800
|
-
}
|
|
6801
|
-
],
|
|
6802
6509
|
"description": "Microsoft Teams team ID. Returned by `ask-marcel-office list-joined-teams`."
|
|
6803
6510
|
},
|
|
6804
6511
|
{
|
|
@@ -6829,12 +6536,6 @@
|
|
|
6829
6536
|
"name": "team-id",
|
|
6830
6537
|
"key": "teamId",
|
|
6831
6538
|
"required": true,
|
|
6832
|
-
"aliases": [
|
|
6833
|
-
{
|
|
6834
|
-
"name": "id",
|
|
6835
|
-
"key": "id"
|
|
6836
|
-
}
|
|
6837
|
-
],
|
|
6838
6539
|
"description": "Microsoft Teams team ID."
|
|
6839
6540
|
}
|
|
6840
6541
|
],
|
|
@@ -6854,12 +6555,6 @@
|
|
|
6854
6555
|
"name": "chat-id",
|
|
6855
6556
|
"key": "chatId",
|
|
6856
6557
|
"required": true,
|
|
6857
|
-
"aliases": [
|
|
6858
|
-
{
|
|
6859
|
-
"name": "id",
|
|
6860
|
-
"key": "id"
|
|
6861
|
-
}
|
|
6862
|
-
],
|
|
6863
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`."
|
|
6864
6559
|
},
|
|
6865
6560
|
{
|
|
@@ -6895,7 +6590,7 @@
|
|
|
6895
6590
|
],
|
|
6896
6591
|
"example": "ask-marcel-office list-teams-chat-history --chat-id '19:abc...@unq.gbl.spaces' --max-pages 5",
|
|
6897
6592
|
"responseShape": "`{ messages: [...], hasMore: boolean, pagesFetched: number, nextSyncState?: string, projection: 'slim' | 'full' }`. Slim projection (default) emits `{ id, sequenceId, composetime, originalarrivaltime, messagetype, from, imdisplayname, content }` per message, with `truncated: true` + `originalContentChars` on entries whose `content` exceeded `--max-content-chars` (default 4096). With `--full true`, returns the raw IC3 substrate shape: `id`, `sequenceId` (monotonic per-chat counter), `composetime`, `originalarrivaltime`, `messagetype`, `content`, `from`, `imdisplayname`, `properties.subject`, etc. **`hasMore: true`** means the safety cap was hit and there is older history beyond what was returned — chain a follow-up call with `--sync-state $(jq -r .data.nextSyncState <prev>)` to continue. **`hasMore: false`** means the chat's earliest message was reached. **Microsoft-internal schema — fields may change without notice.**",
|
|
6898
|
-
"needsSubstrateToken":
|
|
6593
|
+
"needsSubstrateToken": "ic3",
|
|
6899
6594
|
"stability": "experimental"
|
|
6900
6595
|
},
|
|
6901
6596
|
{
|
|
@@ -6910,18 +6605,12 @@
|
|
|
6910
6605
|
"name": "chat-id",
|
|
6911
6606
|
"key": "chatId",
|
|
6912
6607
|
"required": true,
|
|
6913
|
-
"aliases": [
|
|
6914
|
-
{
|
|
6915
|
-
"name": "id",
|
|
6916
|
-
"key": "id"
|
|
6917
|
-
}
|
|
6918
|
-
],
|
|
6919
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`."
|
|
6920
6609
|
}
|
|
6921
6610
|
],
|
|
6922
6611
|
"example": "ask-marcel-office list-teams-chat-messages --chat-id '19:abc...@unq.gbl.spaces'",
|
|
6923
6612
|
"responseShape": "Substrate envelope: `{ messages: [...], messageToken: string }`. Returns up to the 200 most recent messages per chat — older history is NOT reachable via this endpoint. Each message has `id`, `from`, `imDisplayName`, `content`, `contentType`, `composeTime`, `originalArrivalTime`, `sequenceId`, etc. `messageToken` is returned for forward compatibility but is currently a static snapshot identifier (server ignores it as a pagination cursor). **Microsoft-internal schema — fields may change without notice.** For history older than the 200 most recent, use `list-teams-chat-history` (rides the IC3 substrate with a working syncState cursor).",
|
|
6924
|
-
"needsSubstrateToken":
|
|
6613
|
+
"needsSubstrateToken": "chatsvcagg",
|
|
6925
6614
|
"stability": "experimental"
|
|
6926
6615
|
},
|
|
6927
6616
|
{
|
|
@@ -6947,7 +6636,7 @@
|
|
|
6947
6636
|
],
|
|
6948
6637
|
"example": "ask-marcel-office list-teams-chats-with-messages --page-size 100",
|
|
6949
6638
|
"responseShape": "`{ chats: [...], continuationToken?: string, hasMoreData?: boolean }`. Each chat carries `id`, `title`, `chatType`, `threadType`, `members[]` (with each member's `mri`, `displayName`, `email`), `createdAt`, AND `lastMessage` (the most recent message body inlined — `content`, `from`, `composeTime`, `imDisplayName`, etc.). When `hasMoreData: true`, chain a follow-up call with `--continuation-token \"$(jq -r .data.continuationToken <prev>)\"`. **Microsoft-internal schema — fields may change without notice; treat the response as semi-structured.**",
|
|
6950
|
-
"needsSubstrateToken":
|
|
6639
|
+
"needsSubstrateToken": "chatsvcagg",
|
|
6951
6640
|
"stability": "experimental"
|
|
6952
6641
|
},
|
|
6953
6642
|
{
|
|
@@ -6962,29 +6651,13 @@
|
|
|
6962
6651
|
"name": "todo-task-list-id",
|
|
6963
6652
|
"key": "todoTaskListId",
|
|
6964
6653
|
"required": true,
|
|
6965
|
-
"description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
|
|
6966
|
-
"aliases": [
|
|
6967
|
-
{
|
|
6968
|
-
"name": "task-list-id",
|
|
6969
|
-
"key": "taskListId"
|
|
6970
|
-
},
|
|
6971
|
-
{
|
|
6972
|
-
"name": "todo-list-id",
|
|
6973
|
-
"key": "todoListId"
|
|
6974
|
-
}
|
|
6975
|
-
]
|
|
6654
|
+
"description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
|
|
6976
6655
|
},
|
|
6977
6656
|
{
|
|
6978
6657
|
"name": "todo-task-id",
|
|
6979
6658
|
"key": "todoTaskId",
|
|
6980
6659
|
"required": true,
|
|
6981
|
-
"description": "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`.
|
|
6982
|
-
"aliases": [
|
|
6983
|
-
{
|
|
6984
|
-
"name": "task-id",
|
|
6985
|
-
"key": "taskId"
|
|
6986
|
-
}
|
|
6987
|
-
]
|
|
6660
|
+
"description": "To Do task ID. Returned by `ask-marcel-office list-todo-tasks`."
|
|
6988
6661
|
},
|
|
6989
6662
|
{
|
|
6990
6663
|
"name": "top",
|
|
@@ -7076,21 +6749,7 @@
|
|
|
7076
6749
|
"name": "todo-task-list-id",
|
|
7077
6750
|
"key": "todoTaskListId",
|
|
7078
6751
|
"required": true,
|
|
7079
|
-
"description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
|
|
7080
|
-
"aliases": [
|
|
7081
|
-
{
|
|
7082
|
-
"name": "id",
|
|
7083
|
-
"key": "id"
|
|
7084
|
-
},
|
|
7085
|
-
{
|
|
7086
|
-
"name": "task-list-id",
|
|
7087
|
-
"key": "taskListId"
|
|
7088
|
-
},
|
|
7089
|
-
{
|
|
7090
|
-
"name": "todo-list-id",
|
|
7091
|
-
"key": "todoListId"
|
|
7092
|
-
}
|
|
7093
|
-
]
|
|
6752
|
+
"description": "To Do task list ID. Returned by `ask-marcel-office list-todo-task-lists`."
|
|
7094
6753
|
},
|
|
7095
6754
|
{
|
|
7096
6755
|
"name": "top",
|
|
@@ -7145,21 +6804,7 @@
|
|
|
7145
6804
|
"name": "todo-task-list-id",
|
|
7146
6805
|
"key": "todoTaskListId",
|
|
7147
6806
|
"required": true,
|
|
7148
|
-
"description": "Microsoft To Do task list ID. Returned by `list-todo-task-lists`."
|
|
7149
|
-
"aliases": [
|
|
7150
|
-
{
|
|
7151
|
-
"name": "id",
|
|
7152
|
-
"key": "id"
|
|
7153
|
-
},
|
|
7154
|
-
{
|
|
7155
|
-
"name": "task-list-id",
|
|
7156
|
-
"key": "taskListId"
|
|
7157
|
-
},
|
|
7158
|
-
{
|
|
7159
|
-
"name": "todo-list-id",
|
|
7160
|
-
"key": "todoListId"
|
|
7161
|
-
}
|
|
7162
|
-
]
|
|
6807
|
+
"description": "Microsoft To Do task list ID. Returned by `list-todo-task-lists`."
|
|
7163
6808
|
}
|
|
7164
6809
|
],
|
|
7165
6810
|
"example": "ask-marcel-office list-todo-tasks-delta --todo-task-list-id 'AAMkAD...'",
|
|
@@ -7227,12 +6872,6 @@
|
|
|
7227
6872
|
"name": "user-id",
|
|
7228
6873
|
"key": "userId",
|
|
7229
6874
|
"required": true,
|
|
7230
|
-
"aliases": [
|
|
7231
|
-
{
|
|
7232
|
-
"name": "id",
|
|
7233
|
-
"key": "id"
|
|
7234
|
-
}
|
|
7235
|
-
],
|
|
7236
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)."
|
|
7237
6876
|
},
|
|
7238
6877
|
{
|
|
@@ -7308,7 +6947,7 @@
|
|
|
7308
6947
|
},
|
|
7309
6948
|
{
|
|
7310
6949
|
"name": "next-page",
|
|
7311
|
-
"summary": "Fetch the next page of a paginated Graph response. Pass the cursor the previous command emitted — in text mode
|
|
6950
|
+
"summary": "Fetch the next page of a paginated Graph response. Pass the cursor the previous command emitted — in text mode the `---` footer prints the whole ready-to-run command (`next: ask-marcel-office next-page --url '<url>'`), so copy the line as-is (the URL is single-quoted because it contains `$`); in JSON mode use the top-level `nextLink` field. Never reach into `data[\"@odata.nextLink\"]`; the CLI strips that and surfaces it as a first-class envelope/footer field. Automatically signs `/me/chats` and `/chats/...` cursors with the M365ChatClient elevated token to match the chat-metadata commands.",
|
|
7312
6951
|
"category": "meta",
|
|
7313
6952
|
"graphMethod": "GET",
|
|
7314
6953
|
"graphPathTemplate": "{url}",
|
|
@@ -7329,7 +6968,7 @@
|
|
|
7329
6968
|
},
|
|
7330
6969
|
{
|
|
7331
6970
|
"name": "read-mail-attachment",
|
|
7332
|
-
"summary": "Read an Outlook mail attachment whatever it is — one command that auto-routes by file type, preferring the content-type when the filename extension is misleading (a real `.jpg` that is actually a spreadsheet still converts), so a caller never has to choose between the convert-mail-attachment-* siblings. A `.zip` fileAttachment is unpacked and every entry converted (mirrors `convert-mail-attachment-zip`, returning the `{ count, files }` envelope; legacy GBK/CP437 names decoded). Any other attachment — docx/xlsx/pptx/odt/ods/odp + macro/template variants → markdown, csv → table, pdf → text layer (with `pageCount`), legacy .xls/.doc extracted, an inner Outlook .msg rendered recursively, plain text passed through, referenceAttachment resolved via `/shares`, and itemAttachment (embedded mail/event/contact) rendered — goes through the same dispatch as `convert-mail-attachment-to-markdown` (returning its `{ contentType, size, text }` envelope). Images, scanned/image-only PDFs, and legacy .ppt return an actionable 415 pointing at `convert-mail-attachment-to-pdf` + a vision model or `get-mail-attachment` for the raw bytes. Pass `--include-metadata true` to append Office side-channel metadata. Use the explicit `convert-mail-attachment-to-markdown` / `-to-pdf` / `-zip` siblings only when you need to force a specific output format.",
|
|
6971
|
+
"summary": "Read an Outlook mail attachment whatever it is — one command that auto-routes by file type, preferring the content-type when the filename extension is misleading (a real `.jpg` that is actually a spreadsheet still converts), so a caller never has to choose between the convert-mail-attachment-* siblings. A `.zip` fileAttachment is unpacked and every entry converted (mirrors `convert-mail-attachment-zip-to-markdown`, returning the `{ count, files }` envelope; legacy GBK/CP437 names decoded). Any other attachment — docx/xlsx/pptx/odt/ods/odp + macro/template variants → markdown, csv → table, pdf → text layer (with `pageCount`), legacy .xls/.doc extracted, an inner Outlook .msg rendered recursively (quoted chain stripped unless `--keep-quoted true`), plain text passed through, referenceAttachment resolved via `/shares`, and itemAttachment (embedded mail/event/contact) rendered — goes through the same dispatch as `convert-mail-attachment-to-markdown` (returning its `{ contentType, size, text }` envelope). Images, scanned/image-only PDFs, and legacy .ppt return an actionable 415 pointing at `convert-mail-attachment-to-pdf` + a vision model or `get-mail-attachment` for the raw bytes. Pass `--include-metadata true` to append Office side-channel metadata. Use the explicit `convert-mail-attachment-to-markdown` / `-to-pdf` / `-zip` siblings only when you need to force a specific output format.",
|
|
7333
6972
|
"category": "mail",
|
|
7334
6973
|
"graphMethod": "GET",
|
|
7335
6974
|
"graphPathTemplate": "/me/messages/{message-id}/attachments/{attachment-id}",
|
|
@@ -7359,10 +6998,23 @@
|
|
|
7359
6998
|
"false"
|
|
7360
6999
|
]
|
|
7361
7000
|
}
|
|
7001
|
+
},
|
|
7002
|
+
{
|
|
7003
|
+
"name": "keep-quoted",
|
|
7004
|
+
"key": "keepQuoted",
|
|
7005
|
+
"required": false,
|
|
7006
|
+
"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`.",
|
|
7007
|
+
"argumentHint": {
|
|
7008
|
+
"kind": "magicValue",
|
|
7009
|
+
"values": [
|
|
7010
|
+
"true",
|
|
7011
|
+
"false"
|
|
7012
|
+
]
|
|
7013
|
+
}
|
|
7362
7014
|
}
|
|
7363
7015
|
],
|
|
7364
7016
|
"example": "ask-marcel-office read-mail-attachment --message-id 'AAMkAD...' --attachment-id 'AAMkAD...attach1'",
|
|
7365
|
-
"responseShape": "Polymorphic by attachment content-type. A zip → `{ count, files: [{ path, contentType, size, text } | { path, note }], truncated? }` (the convert-mail-attachment-zip shape). Everything else → `{ contentType: \"text/markdown\" | \"text/plain\", size, text, pageCount? }` (the convert-mail-attachment-to-markdown shape; `pageCount` present for PDF sources). Unsupported types (image / scanned PDF / legacy .ppt) return an api_error (415/400) naming the right next command.",
|
|
7017
|
+
"responseShape": "Polymorphic by attachment content-type. A zip → `{ count, files: [{ path, contentType, size, text } | { path, note }], truncated? }` (the convert-mail-attachment-zip-to-markdown shape). Everything else → `{ contentType: \"text/markdown\" | \"text/plain\", size, text, pageCount? }` (the convert-mail-attachment-to-markdown shape; `pageCount` present for PDF sources). Unsupported types (image / scanned PDF / legacy .ppt) return an api_error (415/400) naming the right next command.",
|
|
7366
7018
|
"producesBytes": true
|
|
7367
7019
|
},
|
|
7368
7020
|
{
|
|
@@ -7385,10 +7037,10 @@
|
|
|
7385
7037
|
},
|
|
7386
7038
|
{
|
|
7387
7039
|
"name": "resolve-drive-share-link",
|
|
7388
|
-
"summary": "
|
|
7040
|
+
"summary": "Resolve a OneDrive / SharePoint sharing URL (a \"Copy link\" address someone sent you) to the file it points at, returning `driveId` + `itemId` ready to feed `get-drive-item`, `download-drive-item-content`, `convert-drive-item-*`, `extract-drive-item-images`, and the rest of the `*-drive-item` family. It encodes the URL to the Graph `/shares/{token}` share token (`u!<base64url>` per [shares-get](https://learn.microsoft.com/en-us/graph/api/shares-get)) and fetches `/shares/{token}/driveItem` in ONE call (basic token, `Files.Read.All`) — a raw sharing URL carries no ids, so this is the entry point into the drive-item family from a shared link. Accepts any `*.sharepoint.com` URL (tenant + `*-my.sharepoint.com` personal OneDrive) and Microsoft's short-link host `1drv.ms`. **Cross-tenant links work too**: when the URL belongs to a tenant you are only a GUEST in, your home token cannot read its SharePoint (Graph answers `invalidAudienceUri` — it cannot mint a SharePoint token for a foreign tenant), so this command identifies the owning tenant from the URL host and retries with a guest token automatically, then returns that tenant as `tenantId` — see `responseShape` for how to pass it on to the follow-up calls.",
|
|
7389
7041
|
"category": "drive",
|
|
7390
7042
|
"graphMethod": "GET",
|
|
7391
|
-
"graphPathTemplate": "{url}",
|
|
7043
|
+
"graphPathTemplate": "/shares/(u!<base64url> of {url})/driveItem",
|
|
7392
7044
|
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/shares-get",
|
|
7393
7045
|
"options": [
|
|
7394
7046
|
{
|
|
@@ -7399,7 +7051,7 @@
|
|
|
7399
7051
|
}
|
|
7400
7052
|
],
|
|
7401
7053
|
"example": "ask-marcel-office resolve-drive-share-link --url 'https://contoso.sharepoint.com/:b:/s/team/EaB1cD2eF...?e=abc'",
|
|
7402
|
-
"responseShape": "`{
|
|
7054
|
+
"responseShape": "`{ driveId, itemId, name, webUrl, size, lastModifiedDateTime, shareToken, tenantId? }`. `driveId` (from the item's `parentReference`) + `itemId` feed every `*-drive-item` command directly — no second call. `shareToken` is the `u!<base64url>` form, kept for reuse against other `/shares/{token}/...` endpoints. **`tenantId` is present ONLY when the link belongs to a partner tenant you are a guest in** — when it is there, pass it as `--tenant-id` to every follow-up `*-drive-item` call (`download-drive-item-content`, `convert-drive-item-*`, `extract-drive-item-images`, `get-drive-item`, …), because `driveId`/`itemId` carry no tenant and those commands would otherwise fail with `invalidAudienceUri`. When `tenantId` is absent the file is in your own tenant and no flag is needed. Any other field is absent/`undefined` when the resolved driveItem omits it (e.g. `size` on a folder)."
|
|
7403
7055
|
},
|
|
7404
7056
|
{
|
|
7405
7057
|
"name": "resolve-mail-link",
|
|
@@ -7439,14 +7091,14 @@
|
|
|
7439
7091
|
},
|
|
7440
7092
|
{
|
|
7441
7093
|
"name": "scopes-check",
|
|
7442
|
-
"summary": "Decode the cached Teams web client access token and return its scopes, audience, and expiry without making a Graph call. Use this as a self-test before running a command an LLM expects to fail with `accessDenied` — if the required scope isn't in the returned list, the call will reject regardless of tenant config. Each command's `scopesRequired` field in `help-json` lists the scopes that command needs; intersect with the array returned here for a pre-flight check (pipe both through `jq` and diff). The `expiresInSeconds` field lets an LLM decide pre-emptively to `login` again — typically worth doing under ~5 minutes (300 s) so a long-running session doesn't hit the wall mid-command. The `elevated` block reports whether the *separate* M365ChatClient-elevated token (needed by the historical-version download / convert commands) is cached and still usable — so a fresh process can pre-flight `deep-scan`-style workloads instead of discovering a 403 mid-run; `available:false` when it is absent, expired, or within the same 5-minute buffer the download path applies. The `chatsvcagg` and `ic3` blocks report the two Teams-chat substrate tokens (used by `list-teams-chat*` / `find-chats-with-user`) the same way; both self-heal from the shared refresh token, so they are informational rather than a preflight gate.",
|
|
7094
|
+
"summary": "Decode the cached Teams web client access token and return its scopes, audience, and expiry without making a Graph call. Use this as a self-test before running a command an LLM expects to fail with `accessDenied` — if the required scope isn't in the returned list, the call will reject regardless of tenant config. Each command's `scopesRequired` field in `help-json` lists the scopes that command needs; intersect with the array returned here for a pre-flight check (pipe both through `jq` and diff). The `expiresInSeconds` field lets an LLM decide pre-emptively to `login` again — typically worth doing under ~5 minutes (300 s) so a long-running session doesn't hit the wall mid-command. The `elevated` block reports whether the *separate* M365ChatClient-elevated token (needed by the historical-version download / convert commands) is cached and still usable — so a fresh process can pre-flight `deep-scan`-style workloads instead of discovering a 403 mid-run; `available:false` when it is absent, expired, or within the same 5-minute buffer the download path applies. The `chatsvcagg` and `ic3` blocks report the two Teams-chat substrate tokens (used by `list-teams-chat*` / `find-chats-with-user`) the same way; both self-heal from the shared refresh token, so they are informational rather than a preflight gate. Every tier block also lists that token's OWN granted scopes (decoded from its `scp` claim, distinct per token) and its `refresh` route (`automatic` = self-heals from the shared refresh token; `interactive` = the elevated tier, which carries no refresh token of its own and is re-captured by a browser login); the `hint` field says how to refresh them.",
|
|
7443
7095
|
"category": "meta",
|
|
7444
7096
|
"graphMethod": "GET",
|
|
7445
7097
|
"graphPathTemplate": "(meta) cached-token introspection — no Graph endpoint",
|
|
7446
7098
|
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/permissions-reference",
|
|
7447
7099
|
"options": [],
|
|
7448
7100
|
"example": "ask-marcel-office scopes-check",
|
|
7449
|
-
"responseShape": "`{ scopes: string[], audience: string, expiresAt: string (ISO 8601), expiresInSeconds: number, elevated:
|
|
7101
|
+
"responseShape": "`{ scopes: string[], audience: string, expiresAt: string (ISO 8601), expiresInSeconds: number, elevated: TokenTier, chatsvcagg: TokenTier, ic3: TokenTier, hint: string }` where `TokenTier = { available: boolean, expiresInSeconds?: number, scopes: string[], refresh: \"automatic\" | \"interactive\", reason?: string }`. Top-level `scopes`/`audience`/`expiresAt`/`expiresInSeconds` describe the basic Teams token (back-compat). Each tier block also carries that token's OWN `scopes` (decoded from its `scp` claim: elevated ~20 Graph scopes, chatsvcagg `user_impersonation`, ic3 `Teams.AccessAsUser.All`) and its `refresh` route (`automatic` = self-heals from the shared refresh token; `interactive` = the elevated token, re-captured only by a browser login). `available` is `true` only when the token is present and beyond the 5-minute buffer; `expiresInSeconds` is the raw remaining seconds (negative when expired) and is omitted when the token is absent. `reason` is present ONLY when `available` is `false` — a plain-language note on why the tier is missing and how to restore it (so an empty `scopes: []` on an absent token is not mistaken for \"no scopes\"); it is omitted when the token is available. `hint` names `login --force` as the single refresh action."
|
|
7450
7102
|
},
|
|
7451
7103
|
{
|
|
7452
7104
|
"name": "search-all-accessible-sites",
|
|
@@ -7473,9 +7125,28 @@
|
|
|
7473
7125
|
"responseShape": "`{ value: [<Microsoft Graph site resource: { id, name, displayName?, webUrl, size?, estimatedFileCount?, … }>], count, fileEstimate?, archivedExcluded?, nonNavigableExcluded?, notFoundExcluded?, archiveProbeErrors?, truncated?: true, archiveProbeTruncated?: true }`. `estimatedFileCount` appears only with `--count-files true` — the security-trimmed `driveItem` (files+folders) estimate scoped to each site, omitted past the 200-site count cap or when the per-site query fails. `value[]` is deduped by site `id` across pages; `count` is the number of distinct sites returned (the authoritative figure). `size` (when present) is the site's DEFAULT document library's total bytes used (`drive.quota.used`, recursive) — folded onto the same per-site probe for free, omitted for sites past the probe ceiling or without a default drive; it is a data-volume signal, not a file count. `fileEstimate` (best-effort, omitted if the extra query fails) is the Microsoft Search index's security-trimmed `driveItem` count — roughly how many files+folders the user can access across all of SharePoint/OneDrive. `truncated: true` means paging stopped early (page ceiling hit, or a later page errored) — narrow with `--query` to see the rest; its absence means the sweep ran to completion. `archivedExcluded` (omitted when 0) counts sites dropped as archived/locked by the per-site probe; `nonNavigableExcluded` counts sites dropped by URL shape (add-in app domains, `/contentstorage/` SharePoint Embedded containers, `/_layouts/` system pages); `notFoundExcluded` counts sites whose probe returned 404. `archiveProbeErrors` (omitted when 0) counts sites whose probe failed for an unrelated reason — those are KEPT, so an archived one could slip through. `archiveProbeTruncated: true` means more sites were returned than the probe ceiling (250); the overflow is kept unprobed — narrow with `--query`.",
|
|
7474
7126
|
"bodyTemplate": "{ requests: [{ entityTypes: ['site'], query: { queryString: '{query}' }, from: <page*25>, size: 25 }] } — `{query}` defaults to `*` (all accessible sites); re-issued per page, advancing `from` by 25 until `moreResultsAvailable` is false"
|
|
7475
7127
|
},
|
|
7128
|
+
{
|
|
7129
|
+
"name": "search-all-files",
|
|
7130
|
+
"summary": "Search EVERY file the signed-in user can access — their personal OneDrive, files shared with them, and every SharePoint and Teams (channel) document library they can open — for a free-text query. Unlike `search-my-documents` (personal OneDrive only) or `search-onedrive-files` (one drive by id), this reaches across all accessible drives via the security-trimmed Microsoft Search index; unlike `microsoft-search-query` it returns FILES ONLY (`entityTypes: [\"driveItem\"]`), not mail/calendar/people/sites. It deep-pages `POST /search/query` with `from`/`size` (200 per page) following the index's `moreResultsAvailable` flag until exhausted, or the ceiling of 25×200 = 5000 files is reached (`truncated: true` — narrow with `--query` to see the rest). Hits are deduped by `hitId`. Each returned `driveItem` carries `id` + `parentReference.driveId`, the pair `download-drive-item-content` / `download-drive-item-as-markdown` need to open it.",
|
|
7131
|
+
"category": "drive",
|
|
7132
|
+
"graphMethod": "POST",
|
|
7133
|
+
"graphPathTemplate": "/search/query",
|
|
7134
|
+
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/search-query",
|
|
7135
|
+
"options": [
|
|
7136
|
+
{
|
|
7137
|
+
"name": "query",
|
|
7138
|
+
"key": "query",
|
|
7139
|
+
"required": true,
|
|
7140
|
+
"description": "KQL / free-text search query. Matches filename, content, and metadata across every drive the user can access. Add `filetype:` to narrow (e.g. `q1 budget filetype:xlsx`), or field operators like `filename:`. Free text works everywhere."
|
|
7141
|
+
}
|
|
7142
|
+
],
|
|
7143
|
+
"example": "ask-marcel-office search-all-files --query 'q1 budget filetype:xlsx'",
|
|
7144
|
+
"responseShape": "`{ value: [<Microsoft Graph driveItem resource: { id, name, webUrl, parentReference: { driveId }, size, … }>], count, truncated?: true }`. `value[]` is deduped by `hitId` across pages; `count` is the number of distinct files returned. `truncated: true` means paging stopped early (page ceiling hit, or a later page errored) — narrow with `--query` to see the rest; its absence means the sweep ran to completion.",
|
|
7145
|
+
"bodyTemplate": "{ requests: [{ entityTypes: ['driveItem'], query: { queryString: '{query}' }, from: <page*200>, size: 200 }] } — re-issued per page, advancing `from` by 200 until `moreResultsAvailable` is false or the 25-page ceiling is hit"
|
|
7146
|
+
},
|
|
7476
7147
|
{
|
|
7477
7148
|
"name": "search-mail-messages",
|
|
7478
|
-
"summary": "Search the signed-in user's entire Outlook mailbox using KQL or free text. Results are ranked by Graph relevance. The CLI ships a slim default `--select=id,subject,from,toRecipients,ccRecipients,receivedDateTime,hasAttachments,isRead,importance,bodyPreview` (same as `list-mail-messages`) so a 3-result page stays ~3 KB instead of ~30 KB. Pass `--select id,subject,body` to widen, or override entirely. Note: Graph does not allow `$search` and `$filter` together — the CLI rejects `--filter` client-side with a pointer to `list-mail-messages` (which supports OData filtering). For sorting, server-side `$orderby` is also not allowed with `$search`; use the relevance ranking Graph returns. **
|
|
7149
|
+
"summary": "Search the signed-in user's entire Outlook mailbox using KQL or free text. Results are ranked by Graph relevance. The CLI ships a slim default `--select=id,subject,from,toRecipients,ccRecipients,receivedDateTime,hasAttachments,isRead,importance,bodyPreview,conversationId` (same as `list-mail-messages`; `conversationId` is included so you can group hits into a thread or feed one to `list-conversation-messages`) so a 3-result page stays ~3 KB instead of ~30 KB. Pass `--select id,subject,body` to widen, or override entirely. Note: Graph does not allow `$search` and `$filter` together — the CLI rejects `--filter` client-side with a pointer to `list-mail-messages` (which supports OData filtering). For sorting, server-side `$orderby` is also not allowed with `$search`; use the relevance ranking Graph returns. **Exact-phrase search works**: `--query '\"budget allocation\"'` and embedded field phrases like `--query 'subject:\"Contoso A2 & B7 timeline\"'` are supported — the CLI escapes your double quotes into KQL phrase quotes, wraps the whole expression in the `\"…\"` Graph requires, and percent-encodes the value so `&`, `#`, and `+` are wire-safe. Pass raw KQL otherwise, e.g. `--query 'subject:invoice from:alice'`.",
|
|
7479
7150
|
"category": "mail",
|
|
7480
7151
|
"graphMethod": "GET",
|
|
7481
7152
|
"graphPathTemplate": "/me/messages?$search=\"{query}\"",
|
|
@@ -7589,12 +7260,6 @@
|
|
|
7589
7260
|
"name": "drive-id",
|
|
7590
7261
|
"key": "driveId",
|
|
7591
7262
|
"required": true,
|
|
7592
|
-
"aliases": [
|
|
7593
|
-
{
|
|
7594
|
-
"name": "id",
|
|
7595
|
-
"key": "id"
|
|
7596
|
-
}
|
|
7597
|
-
],
|
|
7598
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."
|
|
7599
7264
|
},
|
|
7600
7265
|
{
|
|
@@ -7643,20 +7308,14 @@
|
|
|
7643
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.",
|
|
7644
7309
|
"category": "notes",
|
|
7645
7310
|
"graphMethod": "GET",
|
|
7646
|
-
"graphPathTemplate": "/me/onenote/pages?$filter=contains(title,'{
|
|
7311
|
+
"graphPathTemplate": "/me/onenote/pages?$filter=contains(title,'{query}')",
|
|
7647
7312
|
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/onenote-list-pages",
|
|
7648
7313
|
"options": [
|
|
7649
7314
|
{
|
|
7650
|
-
"name": "
|
|
7651
|
-
"key": "
|
|
7315
|
+
"name": "query",
|
|
7316
|
+
"key": "query",
|
|
7652
7317
|
"required": true,
|
|
7653
|
-
"description": "Substring to look for inside OneNote page
|
|
7654
|
-
"aliases": [
|
|
7655
|
-
{
|
|
7656
|
-
"name": "query",
|
|
7657
|
-
"key": "query"
|
|
7658
|
-
}
|
|
7659
|
-
]
|
|
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."
|
|
7660
7319
|
},
|
|
7661
7320
|
{
|
|
7662
7321
|
"name": "top",
|
|
@@ -7689,7 +7348,7 @@
|
|
|
7689
7348
|
"description": "OData $expand: navigation properties to include inline (e.g. `attachments`). Increases response size; use sparingly."
|
|
7690
7349
|
}
|
|
7691
7350
|
],
|
|
7692
|
-
"example": "ask-marcel-office search-onenote-pages --
|
|
7351
|
+
"example": "ask-marcel-office search-onenote-pages --query 'meeting notes' --top 25",
|
|
7693
7352
|
"responseShape": "collection of Microsoft Graph `onenotePage` resources under `value[]` whose title contains the substring",
|
|
7694
7353
|
"pagination": true
|
|
7695
7354
|
},
|
|
@@ -7750,23 +7409,17 @@
|
|
|
7750
7409
|
},
|
|
7751
7410
|
{
|
|
7752
7411
|
"name": "update-mail-draft",
|
|
7753
|
-
"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.
|
|
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.",
|
|
7754
7413
|
"category": "mail",
|
|
7755
7414
|
"graphMethod": "PATCH",
|
|
7756
|
-
"graphPathTemplate": "/me/messages/{message-id}",
|
|
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})",
|
|
7757
7416
|
"graphDocsUrl": "https://learn.microsoft.com/en-us/graph/api/message-update",
|
|
7758
7417
|
"options": [
|
|
7759
7418
|
{
|
|
7760
7419
|
"name": "message-id",
|
|
7761
7420
|
"key": "messageId",
|
|
7762
7421
|
"required": true,
|
|
7763
|
-
"
|
|
7764
|
-
{
|
|
7765
|
-
"name": "id",
|
|
7766
|
-
"key": "id"
|
|
7767
|
-
}
|
|
7768
|
-
],
|
|
7769
|
-
"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.",
|
|
7770
7423
|
"argumentHint": {
|
|
7771
7424
|
"kind": "idOrName"
|
|
7772
7425
|
}
|
|
@@ -7781,13 +7434,32 @@
|
|
|
7781
7434
|
"name": "body-content",
|
|
7782
7435
|
"key": "bodyContent",
|
|
7783
7436
|
"required": false,
|
|
7784
|
-
"description": "New email body content. Replaces the
|
|
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."
|
|
7438
|
+
},
|
|
7439
|
+
{
|
|
7440
|
+
"name": "comment",
|
|
7441
|
+
"key": "comment",
|
|
7442
|
+
"required": false,
|
|
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."
|
|
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
|
+
}
|
|
7785
7457
|
},
|
|
7786
7458
|
{
|
|
7787
7459
|
"name": "body-content-type",
|
|
7788
7460
|
"key": "bodyContentType",
|
|
7789
7461
|
"required": false,
|
|
7790
|
-
"description": "
|
|
7462
|
+
"description": "Format of --body-content, or of --comment in comment mode: Text (default) or HTML. With --comment on an HTML draft, Text is escaped into the draft (markup shows as characters) and HTML is spliced in as markup; HTML is refused on a plain-text draft. The draft keeps its own body format either way - this flag describes what you are passing, not what the draft becomes.",
|
|
7791
7463
|
"argumentHint": {
|
|
7792
7464
|
"kind": "magicValue",
|
|
7793
7465
|
"values": [
|
|
@@ -7800,19 +7472,19 @@
|
|
|
7800
7472
|
"name": "to-recipients",
|
|
7801
7473
|
"key": "toRecipients",
|
|
7802
7474
|
"required": false,
|
|
7803
|
-
"description": "Comma-separated list of recipient email addresses. Replaces the entire toRecipients list."
|
|
7475
|
+
"description": "Comma-separated list of recipient email addresses. Replaces the entire toRecipients list. Pass an empty string to CLEAR the list (the only way to drop recipients a reply or forward inherited)."
|
|
7804
7476
|
},
|
|
7805
7477
|
{
|
|
7806
7478
|
"name": "cc-recipients",
|
|
7807
7479
|
"key": "ccRecipients",
|
|
7808
7480
|
"required": false,
|
|
7809
|
-
"description": "Comma-separated list of CC recipient email addresses. Replaces the entire ccRecipients list."
|
|
7481
|
+
"description": "Comma-separated list of CC recipient email addresses. Replaces the entire ccRecipients list. Pass an empty string to CLEAR the list (the only way to drop recipients a reply or forward inherited)."
|
|
7810
7482
|
},
|
|
7811
7483
|
{
|
|
7812
7484
|
"name": "bcc-recipients",
|
|
7813
7485
|
"key": "bccRecipients",
|
|
7814
7486
|
"required": false,
|
|
7815
|
-
"description": "Comma-separated list of BCC recipient email addresses. Replaces the entire bccRecipients list."
|
|
7487
|
+
"description": "Comma-separated list of BCC recipient email addresses. Replaces the entire bccRecipients list. Pass an empty string to CLEAR the list (the only way to drop recipients a reply or forward inherited)."
|
|
7816
7488
|
},
|
|
7817
7489
|
{
|
|
7818
7490
|
"name": "importance",
|
|
@@ -7830,8 +7502,8 @@
|
|
|
7830
7502
|
}
|
|
7831
7503
|
],
|
|
7832
7504
|
"example": "ask-marcel-office update-mail-draft --message-id \"AAMkAD...\" --subject \"Updated: Q3 Report\" --to-recipients \"alice@example.com,charlie@example.com\"",
|
|
7833
|
-
"responseShape": "
|
|
7834
|
-
"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",
|
|
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`.",
|
|
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",
|
|
7835
7507
|
"mutates": true
|
|
7836
7508
|
}
|
|
7837
7509
|
]
|