ask-marcel-office-cli 0.5.5 → 1.4.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 +92 -0
- package/README.md +147 -221
- package/dist/cli.js +99348 -14825
- package/dist/commands.json +5870 -789
- package/dist/composition/build-deps.d.ts +1 -0
- package/dist/composition/cli.d.ts +2 -0
- package/dist/domain/iso-datetime.d.ts +30 -0
- package/dist/index.js +97246 -13703
- package/dist/infra/auth.d.ts +61 -3
- package/dist/infra/browser-auth.d.ts +163 -1
- package/dist/infra/graph-client.d.ts +99 -2
- package/dist/infra/mammoth-adapter.d.ts +4 -0
- package/dist/infra/network-error.d.ts +9 -0
- package/dist/infra/sheetjs-adapter.d.ts +9 -0
- package/dist/infra/turndown-adapter.d.ts +4 -0
- package/dist/presenter/error-hints.d.ts +41 -0
- package/dist/presenter/output-text.d.ts +2 -0
- package/dist/presenter/output.d.ts +5 -2
- package/dist/use-cases/commands/build-command.d.ts +67 -1
- package/dist/use-cases/commands/command-types.d.ts +108 -3
- package/dist/use-cases/commands/convert-mail-attachment-to-markdown.d.ts +11 -0
- package/dist/use-cases/commands/convert-mail-attachment-to-pdf.d.ts +11 -0
- package/dist/use-cases/commands/convert-mail-to-markdown.d.ts +14 -0
- package/dist/use-cases/commands/docs-render.d.ts +10 -1
- package/dist/use-cases/commands/docs.d.ts +44 -1
- package/dist/use-cases/commands/docx-to-markdown.d.ts +11 -0
- package/dist/use-cases/commands/{download-drive-item-version-content.d.ts → download-drive-item-as-markdown.d.ts} +0 -1
- package/dist/use-cases/commands/download-drive-item-as-pdf.d.ts +11 -0
- package/dist/use-cases/commands/download-drive-item-version.d.ts +17 -0
- package/dist/use-cases/commands/download-onedrive-file-content.d.ts +2 -2
- package/dist/use-cases/commands/embedded-item-to-markdown.d.ts +59 -0
- package/dist/use-cases/commands/excel-error.d.ts +6 -0
- package/dist/use-cases/commands/extract-sharepoint-links-in-mail.d.ts +26 -0
- package/dist/use-cases/commands/fetch-raw-bytes.d.ts +56 -0
- package/dist/use-cases/commands/find-chats-with-user.d.ts +10 -0
- package/dist/use-cases/commands/format-zod-error.d.ts +14 -0
- package/dist/use-cases/commands/get-calendar-event.d.ts +1 -5
- package/dist/use-cases/commands/get-calendar-view.d.ts +1 -6
- package/dist/use-cases/commands/get-channel-files-folder.d.ts +4 -0
- package/dist/use-cases/commands/get-chat.d.ts +4 -0
- package/dist/use-cases/commands/get-current-user.d.ts +1 -3
- package/dist/use-cases/commands/get-drive-delta.d.ts +1 -6
- package/dist/use-cases/commands/get-drive-item-analytics.d.ts +9 -0
- package/dist/use-cases/commands/get-drive-item-created-by-user.d.ts +4 -0
- package/dist/use-cases/commands/get-drive-item-last-modified-by-user.d.ts +4 -0
- package/dist/use-cases/commands/get-drive-item-list-item.d.ts +4 -0
- package/dist/use-cases/commands/get-drive-item.d.ts +1 -6
- package/dist/use-cases/commands/get-drive-root-delta.d.ts +4 -0
- package/dist/use-cases/commands/get-drive-root-item.d.ts +1 -5
- package/dist/use-cases/commands/get-drive-special-folder.d.ts +4 -0
- package/dist/use-cases/commands/get-excel-range.d.ts +1 -1
- package/dist/use-cases/commands/get-excel-table.d.ts +1 -1
- package/dist/use-cases/commands/get-excel-used-range.d.ts +15 -0
- package/dist/use-cases/commands/get-group-calendar-view.d.ts +4 -0
- package/dist/use-cases/commands/get-group.d.ts +4 -0
- package/dist/use-cases/commands/get-mail-attachment.d.ts +4 -2
- package/dist/use-cases/commands/get-mail-message-mime.d.ts +8 -0
- package/dist/use-cases/commands/get-mail-message.d.ts +1 -5
- package/dist/use-cases/commands/get-mail-rule.d.ts +9 -0
- package/dist/use-cases/commands/get-mailbox-settings.d.ts +1 -1
- package/dist/use-cases/commands/get-my-calendar.d.ts +4 -0
- package/dist/use-cases/commands/get-my-manager.d.ts +9 -0
- package/dist/use-cases/commands/get-onenote-page-as-markdown.d.ts +10 -0
- package/dist/use-cases/commands/get-organization.d.ts +4 -0
- package/dist/use-cases/commands/get-shared-calendar-view.d.ts +4 -0
- package/dist/use-cases/commands/get-shared-mailbox-message.d.ts +4 -0
- package/dist/use-cases/commands/get-sharepoint-list-column.d.ts +4 -0
- package/dist/use-cases/commands/get-sharepoint-site-drive-by-id.d.ts +1 -6
- package/dist/use-cases/commands/get-sharepoint-site-list-item.d.ts +1 -7
- package/dist/use-cases/commands/get-sharepoint-site-list.d.ts +1 -6
- package/dist/use-cases/commands/get-sharepoint-site-onenote-page-content.d.ts +9 -0
- package/dist/use-cases/commands/get-sharepoint-site.d.ts +1 -5
- package/dist/use-cases/commands/get-site-analytics.d.ts +8 -0
- package/dist/use-cases/commands/get-specific-calendar-event.d.ts +1 -6
- package/dist/use-cases/commands/get-specific-calendar-view.d.ts +1 -7
- package/dist/use-cases/commands/get-team-channel.d.ts +3 -7
- package/dist/use-cases/commands/get-team-primary-channel.d.ts +4 -0
- package/dist/use-cases/commands/get-team.d.ts +1 -5
- package/dist/use-cases/commands/get-teams-chat-message.d.ts +9 -0
- package/dist/use-cases/commands/get-todo-task.d.ts +1 -6
- package/dist/use-cases/commands/get-user-manager.d.ts +10 -0
- package/dist/use-cases/commands/graph-scopes.d.ts +29 -0
- package/dist/use-cases/commands/inline-image-embedder.d.ts +20 -0
- package/dist/use-cases/commands/iso-datetime-schema.d.ts +21 -0
- package/dist/use-cases/commands/link-shape.d.ts +13 -0
- package/dist/use-cases/commands/list-all-onenote-sections.d.ts +1 -3
- package/dist/use-cases/commands/list-calendar-event-instances.d.ts +3 -9
- package/dist/use-cases/commands/list-calendar-events-delta.d.ts +5 -3
- package/dist/use-cases/commands/list-calendar-events.d.ts +1 -3
- package/dist/use-cases/commands/list-calendar-group-calendars.d.ts +4 -0
- package/dist/use-cases/commands/list-calendar-groups.d.ts +4 -0
- package/dist/use-cases/commands/list-calendar-view-delta.d.ts +5 -4
- package/dist/use-cases/commands/list-calendars.d.ts +1 -3
- package/dist/use-cases/commands/list-chat-members.d.ts +3 -6
- package/dist/use-cases/commands/list-chats.d.ts +4 -0
- package/dist/use-cases/commands/list-conversation-messages.d.ts +12 -0
- package/dist/use-cases/commands/list-drive-item-permissions.d.ts +1 -6
- package/dist/use-cases/commands/list-drive-item-thumbnails.d.ts +4 -0
- package/dist/use-cases/commands/list-drive-item-versions.d.ts +1 -6
- package/dist/use-cases/commands/list-drives.d.ts +1 -3
- package/dist/use-cases/commands/list-excel-comments.d.ts +5 -0
- package/dist/use-cases/commands/list-excel-defined-names.d.ts +5 -0
- package/dist/use-cases/commands/list-excel-table-rows.d.ts +2 -7
- package/dist/use-cases/commands/list-excel-tables.d.ts +2 -6
- package/dist/use-cases/commands/list-excel-worksheet-charts.d.ts +5 -0
- package/dist/use-cases/commands/list-excel-worksheet-pivot-tables.d.ts +5 -0
- package/dist/use-cases/commands/list-excel-worksheets.d.ts +2 -6
- package/dist/use-cases/commands/list-focused-inbox-overrides.d.ts +4 -0
- package/dist/use-cases/commands/list-folder-files.d.ts +1 -6
- package/dist/use-cases/commands/list-followed-drive-items.d.ts +4 -0
- package/dist/use-cases/commands/list-group-conversations.d.ts +4 -0
- package/dist/use-cases/commands/list-group-events.d.ts +4 -0
- package/dist/use-cases/commands/list-group-members.d.ts +4 -0
- package/dist/use-cases/commands/list-group-owners.d.ts +4 -0
- package/dist/use-cases/commands/list-group-threads.d.ts +4 -0
- package/dist/use-cases/commands/list-groups.d.ts +4 -0
- package/dist/use-cases/commands/list-incomplete-planner-tasks.d.ts +10 -3
- package/dist/use-cases/commands/list-incomplete-todo-tasks.d.ts +8 -2
- package/dist/use-cases/commands/list-mail-attachments.d.ts +8 -2
- package/dist/use-cases/commands/list-mail-child-folders.d.ts +1 -5
- package/dist/use-cases/commands/list-mail-folder-messages-delta.d.ts +4 -0
- package/dist/use-cases/commands/list-mail-folder-messages.d.ts +1 -5
- package/dist/use-cases/commands/list-mail-folders.d.ts +1 -3
- package/dist/use-cases/commands/list-mail-messages.d.ts +1 -3
- package/dist/use-cases/commands/list-mail-rules.d.ts +1 -1
- package/dist/use-cases/commands/list-my-direct-reports.d.ts +13 -0
- package/dist/use-cases/commands/list-my-memberships.d.ts +4 -0
- package/dist/use-cases/commands/list-my-transitive-memberships.d.ts +4 -0
- package/dist/use-cases/commands/list-onenote-notebook-sections.d.ts +1 -5
- package/dist/use-cases/commands/list-onenote-notebooks.d.ts +1 -3
- package/dist/use-cases/commands/list-onenote-section-pages.d.ts +1 -5
- package/dist/use-cases/commands/list-outlook-categories.d.ts +6 -0
- package/dist/use-cases/commands/list-plan-buckets.d.ts +1 -5
- package/dist/use-cases/commands/list-planner-plans.d.ts +1 -3
- package/dist/use-cases/commands/list-planner-tasks.d.ts +1 -3
- package/dist/use-cases/commands/list-recent-files.d.ts +4 -0
- package/dist/use-cases/commands/list-recently-used-insights.d.ts +4 -0
- package/dist/use-cases/commands/list-relevant-people.d.ts +4 -0
- package/dist/use-cases/commands/list-room-lists.d.ts +4 -0
- package/dist/use-cases/commands/list-rooms.d.ts +4 -0
- package/dist/use-cases/commands/list-sensitivity-labels.d.ts +4 -0
- package/dist/use-cases/commands/list-shared-calendar-events.d.ts +4 -0
- package/dist/use-cases/commands/list-shared-insights.d.ts +4 -0
- package/dist/use-cases/commands/list-shared-mailbox-folder-messages.d.ts +4 -0
- package/dist/use-cases/commands/list-shared-mailbox-messages.d.ts +4 -0
- package/dist/use-cases/commands/list-shared-with-me.d.ts +6 -0
- package/dist/use-cases/commands/list-sharepoint-list-columns.d.ts +4 -0
- package/dist/use-cases/commands/list-sharepoint-list-item-versions.d.ts +4 -0
- package/dist/use-cases/commands/list-sharepoint-site-drives.d.ts +1 -5
- package/dist/use-cases/commands/list-sharepoint-site-list-items.d.ts +1 -6
- package/dist/use-cases/commands/list-sharepoint-site-lists.d.ts +7 -2
- package/dist/use-cases/commands/list-sharepoint-site-onenote-notebook-sections.d.ts +5 -0
- package/dist/use-cases/commands/list-sharepoint-site-onenote-notebooks.d.ts +5 -0
- package/dist/use-cases/commands/list-sharepoint-site-onenote-section-pages.d.ts +5 -0
- package/dist/use-cases/commands/list-sharepoint-site-pages.d.ts +4 -0
- package/dist/use-cases/commands/list-site-columns.d.ts +4 -0
- package/dist/use-cases/commands/list-site-content-types.d.ts +4 -0
- package/dist/use-cases/commands/list-specific-calendar-events.d.ts +1 -5
- package/dist/use-cases/commands/list-team-channels.d.ts +1 -5
- package/dist/use-cases/commands/list-team-installed-apps.d.ts +8 -0
- package/dist/use-cases/commands/list-teams-chat-history.d.ts +16 -0
- package/dist/use-cases/commands/list-teams-chat-messages.d.ts +8 -0
- package/dist/use-cases/commands/list-teams-chats-with-messages.d.ts +9 -0
- package/dist/use-cases/commands/list-todo-linked-resources.d.ts +1 -6
- package/dist/use-cases/commands/list-todo-task-lists.d.ts +1 -3
- package/dist/use-cases/commands/list-todo-tasks-delta.d.ts +8 -0
- package/dist/use-cases/commands/list-todo-tasks.d.ts +8 -2
- package/dist/use-cases/commands/list-trending-insights.d.ts +4 -0
- package/dist/use-cases/commands/list-user-direct-reports.d.ts +4 -0
- package/dist/use-cases/commands/markdown-pipeline.d.ts +23 -0
- package/dist/use-cases/commands/microsoft-search-query.d.ts +8 -0
- package/dist/use-cases/commands/my-quick-context.d.ts +6 -0
- package/dist/use-cases/commands/next-page.d.ts +2 -2
- package/dist/use-cases/commands/odata-query.d.ts +90 -0
- package/dist/use-cases/commands/office-to-markdown.d.ts +6 -0
- package/dist/use-cases/commands/onenote-5k-limit.d.ts +3 -0
- package/dist/use-cases/commands/output-path.d.ts +37 -0
- package/dist/use-cases/commands/resolve-calendar-link.d.ts +8 -0
- package/dist/use-cases/commands/resolve-drive-share-link.d.ts +8 -0
- package/dist/use-cases/commands/resolve-mail-link.d.ts +8 -0
- package/dist/use-cases/commands/resolve-teams-link.d.ts +8 -0
- package/dist/use-cases/commands/scopes-check.d.ts +6 -0
- package/dist/use-cases/commands/search-mail-messages.d.ts +3 -6
- package/dist/use-cases/commands/search-my-documents.d.ts +1 -5
- package/dist/use-cases/commands/search-onedrive-files.d.ts +1 -8
- package/dist/use-cases/commands/search-onenote-pages.d.ts +7 -2
- package/dist/use-cases/commands/search-sharepoint-sites-by-name.d.ts +1 -5
- package/dist/use-cases/commands/sharepoint-link-extractor.d.ts +14 -0
- package/dist/use-cases/commands/text-passthrough.d.ts +24 -0
- package/dist/use-cases/commands/version-id.d.ts +19 -0
- package/dist/use-cases/commands/xlsx-to-markdown.d.ts +6 -0
- package/dist/use-cases/ports/filesystem.d.ts +8 -0
- package/docs/COMMANDS.md +243 -0
- package/docs/USAGE.md +249 -0
- package/docs/commands.json +5870 -789
- package/package.json +11 -2
- /package/dist/use-cases/commands/{search-sharepoint-sites.d.ts → list-mail-folders-delta.d.ts} +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `ask-marcel-office-cli` are documented here.
|
|
4
|
+
|
|
5
|
+
## 1.0.0
|
|
6
|
+
|
|
7
|
+
The first stable release. Two breaking changes consolidate the public output
|
|
8
|
+
contract; the rest is additive.
|
|
9
|
+
|
|
10
|
+
### Breaking — output contract
|
|
11
|
+
|
|
12
|
+
- **Errors emit on stdout**, not stderr. `process.exitCode = 1` still
|
|
13
|
+
distinguishes failure, so shell scripts that branch on the exit code keep
|
|
14
|
+
working — but anything that read errors from stderr (`cmd 2>err.json`) needs
|
|
15
|
+
to merge streams or read stdout instead. An LLM piping `ask-marcel <cmd>
|
|
16
|
+
| jq` no longer needs `2>&1`.
|
|
17
|
+
- **Every command output is wrapped in the v1 envelope**:
|
|
18
|
+
- Success: `{ ok: true, data: <payload>, nextLink?: string, count?: number }`
|
|
19
|
+
- Error: `{ ok: false, error: "<message>" }`
|
|
20
|
+
|
|
21
|
+
`@odata.nextLink` and `@odata.count` from the underlying Graph payload are
|
|
22
|
+
lifted to the top of the envelope and removed from `data`. Consumers who
|
|
23
|
+
parsed `value[0]` as the first item now read `data.value[0]`.
|
|
24
|
+
|
|
25
|
+
### Added — OData query passthrough on every list/search command
|
|
26
|
+
|
|
27
|
+
Every `list-*` / `search-*` / `get-*-delta` command now accepts the six
|
|
28
|
+
standard OData query parameters as optional flags, so an LLM can shrink large
|
|
29
|
+
responses on the fly:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
--top <n> maximum items per page
|
|
33
|
+
--skip <n> offset
|
|
34
|
+
--select <csv> comma-separated field list (huge payload-size win)
|
|
35
|
+
--filter <kql> server-side predicate
|
|
36
|
+
--orderby <kql> sort expression
|
|
37
|
+
--expand <nav> inline navigation properties
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Four commands keep `buildCommand` because their hard-coded `$filter` would
|
|
41
|
+
collide with a user-supplied `--filter`: `list-conversation-messages`,
|
|
42
|
+
`list-incomplete-todo-tasks`, `list-incomplete-planner-tasks`,
|
|
43
|
+
`search-onenote-pages`.
|
|
44
|
+
|
|
45
|
+
### Added — `my-quick-context`
|
|
46
|
+
|
|
47
|
+
New meta command that issues five Graph calls in parallel (`/me`, `/me/drive`,
|
|
48
|
+
`/me/mailFolders/inbox`, `/me/todo/lists`, `/me/calendar`) and returns
|
|
49
|
+
`{ user, primaryDriveId, inboxId, todoLists, primaryCalendarId }` in one
|
|
50
|
+
round trip. Replaces the audit's 5-call discovery chain.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- `microsoft-search-query` no longer 400s. Splits `entityTypes` into two
|
|
55
|
+
`requests[]` entries so Graph stops rejecting `person` mixed with
|
|
56
|
+
file/mail/event types.
|
|
57
|
+
- `list-conversation-messages` no longer trips Graph's `InefficientFilter`.
|
|
58
|
+
Drops the `$orderby=receivedDateTime` from the OData query.
|
|
59
|
+
- `list-sharepoint-site-items` is removed. Microsoft Graph has no list-less
|
|
60
|
+
site/items collection endpoint; `get-sharepoint-site-item`'s docstring now
|
|
61
|
+
points at the two-step discovery chain
|
|
62
|
+
(`list-sharepoint-site-lists` → `list-sharepoint-site-list-items`) that
|
|
63
|
+
Graph actually supports.
|
|
64
|
+
- `list-groups` summary no longer advertises a `--top` flag it didn't
|
|
65
|
+
register. Project-wide invariant added so every `--flag` mentioned in any
|
|
66
|
+
command summary must be a real option or alias on that command.
|
|
67
|
+
- `next-page` routes nextLinks under `/me/chats` and `/chats/...` via the
|
|
68
|
+
elevated M365ChatClient token. Chat pagination no longer 403s.
|
|
69
|
+
- `search-onenote-pages` accepts `--query` as an alias for
|
|
70
|
+
`--title-substring`, matching the convention used by every other search
|
|
71
|
+
command.
|
|
72
|
+
|
|
73
|
+
### Added — flag aliases
|
|
74
|
+
|
|
75
|
+
- `--todo-list-id` is now accepted by every command that takes
|
|
76
|
+
`--todo-task-list-id` (`--task-list-id` alias preserved).
|
|
77
|
+
- `get-sharepoint-site-item` accepts `--list-item-id` (alias for `--item-id`).
|
|
78
|
+
`get-sharepoint-site-list-item` accepts `--item-id` (alias for
|
|
79
|
+
`--list-item-id`). LLMs that write either spelling from memory now hit the
|
|
80
|
+
right flag.
|
|
81
|
+
|
|
82
|
+
### Quality
|
|
83
|
+
|
|
84
|
+
- Bun `JSON.stringify` already escapes every U+0000–U+001F control character
|
|
85
|
+
and U+2028 / U+2029 separator. The audit's "raw control chars" claim in
|
|
86
|
+
the four insight commands does not reproduce against the actual code path;
|
|
87
|
+
regression-guard tests pin the contract.
|
|
88
|
+
|
|
89
|
+
## Older
|
|
90
|
+
|
|
91
|
+
Earlier history is in the git log. See `git log --oneline` for individual
|
|
92
|
+
commits up to and including v0.11.0.
|
package/README.md
CHANGED
|
@@ -1,265 +1,191 @@
|
|
|
1
1
|
# ask-marcel-office-cli
|
|
2
2
|
|
|
3
|
-
Microsoft Graph CLI
|
|
4
|
-
|
|
5
|
-
## Commands
|
|
6
|
-
|
|
7
|
-
### Authentication
|
|
8
|
-
|
|
9
|
-
| Command | Description |
|
|
10
|
-
|---------|-------------|
|
|
11
|
-
| `login` | Authenticate (cached → refresh → browser fallback) |
|
|
12
|
-
| `logout` | Clear cached tokens |
|
|
13
|
-
| `update` | Update ask-marcel to the latest version on npm (auto-detects npm vs bun) |
|
|
14
|
-
| `docs <cmd>` | Print Markdown docs for a single command (full machine-readable manifest at [`docs/commands.json`](docs/commands.json) or via `import manifest from 'ask-marcel-office-cli/commands.json'`) |
|
|
15
|
-
|
|
16
|
-
<!-- AUTO-GENERATED-COMMANDS:BEGIN -->
|
|
17
|
-
|
|
18
|
-
### OneDrive Files
|
|
19
|
-
|
|
20
|
-
| Command | Description | Required params | Graph endpoint |
|
|
21
|
-
|---------|-------------|-----------------|----------------|
|
|
22
|
-
| `download-drive-item-version-content` | Download the binary content of a specific *non-current* historical version of a OneDrive / SharePoint file. Graph refuses to serve the current version through this endpoint with "You cannot get the content of the current version" — for the current version use `download-onedrive-file-content` instead. Same envelope as that command (302 → downloadUrl, or base64 bytes). | `--drive-id`, `--item-id`, `--version-id` | `GET /drives/{drive-id}/items/{item-id}/versions/{version-id}/content` |
|
|
23
|
-
| `download-onedrive-file-content` | Download the binary content of a file stored in OneDrive / SharePoint. Graph normally returns a 302 redirect to a pre-signed CDN URL, surfaced as `@microsoft.graph.downloadUrl`; if it returns bytes directly they are base64-encoded for safe JSON output. | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}/content` |
|
|
24
|
-
| `get-drive-delta` | Get the incremental change set (added / modified / deleted items) under a OneDrive / SharePoint folder. Use the `@odata.deltaLink` from a previous response to resume. | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}/delta()` |
|
|
25
|
-
| `get-drive-item` | Get the metadata (driveItem resource) of a single file or folder in OneDrive / SharePoint. | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}` |
|
|
26
|
-
| `get-drive-root-item` | Get the root folder (driveItem) of a OneDrive / SharePoint drive. | `--drive-id` | `GET /drives/{drive-id}/root` |
|
|
27
|
-
| `list-drive-item-permissions` | List the sharing permissions on a OneDrive / SharePoint file or folder. | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}/permissions` |
|
|
28
|
-
| `list-drive-item-versions` | List the historical versions of a OneDrive / SharePoint file (each save creates a new version). | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}/versions` |
|
|
29
|
-
| `list-drives` | List all OneDrive / SharePoint drives the signed-in user has access to. | _(none)_ | `GET /me/drives` |
|
|
30
|
-
| `list-folder-files` | List the children (files and subfolders) of a folder in OneDrive / SharePoint. | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}/children` |
|
|
31
|
-
| `search-my-documents` | Search the signed-in user’s default OneDrive for documents matching a free-text query (filename, content, metadata). | `--query` | `GET /me/drive/search(q='{query}')` |
|
|
32
|
-
| `search-onedrive-files` | Search a single OneDrive / SharePoint drive for files and folders matching a free-text query. | `--drive-id`, `--query` | `GET /drives/{drive-id}/search(q='{query}')` |
|
|
33
|
-
|
|
34
|
-
### Excel (workbook files)
|
|
35
|
-
|
|
36
|
-
| Command | Description | Required params | Graph endpoint |
|
|
37
|
-
|---------|-------------|-----------------|----------------|
|
|
38
|
-
| `get-excel-range` | Get the cell values, formulas, and formats of a specific Excel range (e.g. `A1:C10`). | `--drive-id`, `--item-id`, `--worksheet-id`, `--address` | `GET /drives/{drive-id}/items/{item-id}/workbook/worksheets/{worksheet-id}/range(address='{address}')` |
|
|
39
|
-
| `get-excel-table` | Get the metadata (style, header row, total row) of a single named Excel table. | `--drive-id`, `--item-id`, `--table-id` | `GET /drives/{drive-id}/items/{item-id}/workbook/tables/{table-id}` |
|
|
40
|
-
| `list-excel-table-rows` | List the data rows of a named Excel table (excluding the header row). | `--drive-id`, `--item-id`, `--table-id` | `GET /drives/{drive-id}/items/{item-id}/workbook/tables/{table-id}/rows` |
|
|
41
|
-
| `list-excel-tables` | List the named tables across every worksheet in an Excel workbook. | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}/workbook/tables` |
|
|
42
|
-
| `list-excel-worksheets` | List the worksheets (tabs) inside an Excel workbook stored in OneDrive / SharePoint. | `--drive-id`, `--item-id` | `GET /drives/{drive-id}/items/{item-id}/workbook/worksheets` |
|
|
43
|
-
|
|
44
|
-
### SharePoint Sites
|
|
45
|
-
|
|
46
|
-
| Command | Description | Required params | Graph endpoint |
|
|
47
|
-
|---------|-------------|-----------------|----------------|
|
|
48
|
-
| `get-sharepoint-site` | Get the metadata of a single SharePoint site by its site ID. | `--site-id` | `GET /sites/{site-id}` |
|
|
49
|
-
| `get-sharepoint-site-by-path` | Resolve a SharePoint site by its hostname + server-relative path. Use this when you have a SharePoint URL (e.g. `https://contoso.sharepoint.com/sites/Marketing`) but no site ID. | `--hostname`, `--path` | `GET /sites/{hostname}:{path}` |
|
|
50
|
-
| `get-sharepoint-site-drive-by-id` | Get the metadata of a single document library (drive) on a SharePoint site by drive ID. | `--site-id`, `--drive-id` | `GET /sites/{site-id}/drives/{drive-id}` |
|
|
51
|
-
| `get-sharepoint-site-list` | Get the metadata (display name, template, columns) of a single SharePoint list. | `--site-id`, `--list-id` | `GET /sites/{site-id}/lists/{list-id}` |
|
|
52
|
-
| `get-sharepoint-site-list-item` | Get a single row (listItem) of a SharePoint list by ID. | `--site-id`, `--list-id`, `--list-item-id` | `GET /sites/{site-id}/lists/{list-id}/items/{list-item-id}` |
|
|
53
|
-
| `list-sharepoint-site-drives` | List the document libraries (drives) attached to a SharePoint site. | `--site-id` | `GET /sites/{site-id}/drives` |
|
|
54
|
-
| `list-sharepoint-site-list-items` | List the rows (listItem resources) of a single SharePoint list. | `--site-id`, `--list-id` | `GET /sites/{site-id}/lists/{list-id}/items` |
|
|
55
|
-
| `list-sharepoint-site-lists` | List all SharePoint lists (custom + built-in document libraries) on a site. | `--site-id` | `GET /sites/{site-id}/lists` |
|
|
56
|
-
| `search-sharepoint-sites` | List the SharePoint sites the signed-in user has access to (returns the followed sites by default). | _(none)_ | `GET /sites` |
|
|
57
|
-
| `search-sharepoint-sites-by-name` | Search the tenant for SharePoint sites whose display name or description matches a free-text query (returns up to 25). | `--query` | `GET /sites?search={query}` |
|
|
58
|
-
|
|
59
|
-
### Tasks (To Do + Planner)
|
|
60
|
-
|
|
61
|
-
| Command | Description | Required params | Graph endpoint |
|
|
62
|
-
|---------|-------------|-----------------|----------------|
|
|
63
|
-
| `get-planner-bucket` | Get the metadata of a single Microsoft Planner bucket (column / lane). | `--planner-bucket-id` | `GET /planner/buckets/{planner-bucket-id}` |
|
|
64
|
-
| `get-planner-plan` | Get the metadata of a single Microsoft Planner plan (title, owner group, container). | `--planner-plan-id` | `GET /planner/plans/{planner-plan-id}` |
|
|
65
|
-
| `get-planner-task` | Get the metadata of a single Microsoft Planner task (title, assignees, dates, completion). | `--planner-task-id` | `GET /planner/tasks/{planner-task-id}` |
|
|
66
|
-
| `get-planner-task-details` | Get the rich details (description, checklist, references) of a Microsoft Planner task. | `--planner-task-id` | `GET /planner/tasks/{planner-task-id}/details` |
|
|
67
|
-
| `get-todo-task` | Get a single Microsoft To Do task by its ID and its parent list ID. | `--todo-task-list-id`, `--todo-task-id` | `GET /me/todo/lists/{todo-task-list-id}/tasks/{todo-task-id}` |
|
|
68
|
-
| `list-incomplete-planner-tasks` | List every incomplete Microsoft Planner task assigned to or owned by the signed-in user, across every plan. | _(none)_ | `GET /me/planner/tasks?$filter=percentComplete ne 100` |
|
|
69
|
-
| `list-incomplete-todo-tasks` | List every incomplete Microsoft To Do task in a given list (status not equal to `completed`). | `--todo-task-list-id` | `GET /me/todo/lists/{todo-task-list-id}/tasks?$filter=status ne 'completed'` |
|
|
70
|
-
| `list-plan-buckets` | List the buckets (columns / lanes) of a Microsoft Planner plan. | `--planner-plan-id` | `GET /planner/plans/{planner-plan-id}/buckets` |
|
|
71
|
-
| `list-plan-tasks` | List every task within a Microsoft Planner plan, regardless of completion status (Graph orders by `orderHint`). Use `list-incomplete-planner-tasks` for the across-plans incomplete view. | `--planner-plan-id` | `GET /planner/plans/{planner-plan-id}/tasks` |
|
|
72
|
-
| `list-planner-plans` | List every Microsoft Planner plan the signed-in user has access to (across every group). Use this to discover plan IDs without needing an existing task as the entry point. | _(none)_ | `GET /me/planner/plans` |
|
|
73
|
-
| `list-planner-tasks` | List every Microsoft Planner task assigned to or owned by the signed-in user, across all plans. | _(none)_ | `GET /me/planner/tasks` |
|
|
74
|
-
| `list-todo-linked-resources` | List the linked resources (URLs, emails, files) attached to a Microsoft To Do task. | `--todo-task-list-id`, `--todo-task-id` | `GET /me/todo/lists/{todo-task-list-id}/tasks/{todo-task-id}/linkedResources` |
|
|
75
|
-
| `list-todo-task-lists` | List the signed-in user’s Microsoft To Do task lists (e.g. `Tasks`, `Flagged Emails`, custom lists). | _(none)_ | `GET /me/todo/lists` |
|
|
76
|
-
| `list-todo-tasks` | List every task in a single Microsoft To Do task list, regardless of completion status. Use `list-incomplete-todo-tasks` if you only want the open ones. | `--todo-task-list-id` | `GET /me/todo/lists/{todo-task-list-id}/tasks` |
|
|
77
|
-
|
|
78
|
-
### Mail
|
|
79
|
-
|
|
80
|
-
| Command | Description | Required params | Graph endpoint |
|
|
81
|
-
|---------|-------------|-----------------|----------------|
|
|
82
|
-
| `get-mail-attachment` | Get a single attachment on an Outlook message (metadata, plus the base64 `contentBytes` for file attachments). | `--message-id`, `--attachment-id` | `GET /me/messages/{message-id}/attachments/{attachment-id}` |
|
|
83
|
-
| `get-mail-message` | Get a single Outlook message by ID, including subject, sender, body, and flags. | `--message-id` | `GET /me/messages/{message-id}` |
|
|
84
|
-
| `get-mailbox-settings` | Get the signed-in user’s Outlook mailbox settings (timezone, working hours, automatic replies). | _(none)_ | `GET /me/mailboxSettings` |
|
|
85
|
-
| `list-mail-attachments` | List the attachments (file, item, reference) on a single Outlook message. | `--message-id` | `GET /me/messages/{message-id}/attachments` |
|
|
86
|
-
| `list-mail-child-folders` | List the subfolders of a single Outlook mail folder (e.g. subfolders of Inbox). | `--mail-folder-id` | `GET /me/mailFolders/{mail-folder-id}/childFolders` |
|
|
87
|
-
| `list-mail-folder-messages` | List the messages inside a specific Outlook mail folder (Inbox, custom folder, etc.). | `--mail-folder-id` | `GET /me/mailFolders/{mail-folder-id}/messages` |
|
|
88
|
-
| `list-mail-folders` | List the top-level mail folders in the signed-in user’s Outlook mailbox (Inbox, Sent Items, etc.). | _(none)_ | `GET /me/mailFolders` |
|
|
89
|
-
| `list-mail-messages` | 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). Use `list-mail-folder-messages` to scope to a single folder such as Inbox. | _(none)_ | `GET /me/messages` |
|
|
90
|
-
| `list-mail-rules` | List the inbox / folder rules attached to a single Outlook mail folder. | `--mail-folder-id` | `GET /me/mailFolders/{mail-folder-id}/messageRules` |
|
|
91
|
-
| `search-mail-messages` | Search the signed-in user’s entire Outlook mailbox using KQL or free text. Results are ranked by Graph relevance. | `--query` | `GET /me/messages?$search="{query}"` |
|
|
92
|
-
|
|
93
|
-
### Notes (OneNote)
|
|
94
|
-
|
|
95
|
-
| Command | Description | Required params | Graph endpoint |
|
|
96
|
-
|---------|-------------|-----------------|----------------|
|
|
97
|
-
| `get-onenote-page-content` | Get the HTML body of a single OneNote page. Returned in a JSON envelope so the HTML survives transport. | `--onenote-page-id` | `GET /me/onenote/pages/{onenote-page-id}/content` |
|
|
98
|
-
| `list-all-onenote-sections` | List every OneNote section the signed-in user can see, across all notebooks. | _(none)_ | `GET /me/onenote/sections` |
|
|
99
|
-
| `list-onenote-notebook-sections` | List the top-level sections of a single OneNote notebook (flat — does NOT recurse into section groups; use `list-all-onenote-sections` to flatten every notebook the user has access to). | `--notebook-id` | `GET /me/onenote/notebooks/{notebook-id}/sections` |
|
|
100
|
-
| `list-onenote-notebooks` | List the OneNote notebooks the signed-in user owns or has access to (sorted by `createdDateTime` desc by Graph; soft-deleted notebooks excluded). | _(none)_ | `GET /me/onenote/notebooks` |
|
|
101
|
-
| `list-onenote-section-pages` | List the pages inside a single OneNote section. | `--onenote-section-id` | `GET /me/onenote/sections/{onenote-section-id}/pages` |
|
|
102
|
-
| `search-onenote-pages` | 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. | `--title-substring` | `GET /me/onenote/pages?$filter=contains(title,'{title-substring}')` |
|
|
103
|
-
|
|
104
|
-
### User
|
|
105
|
-
|
|
106
|
-
| Command | Description | Required params | Graph endpoint |
|
|
107
|
-
|---------|-------------|-----------------|----------------|
|
|
108
|
-
| `get-current-user` | Return the signed-in user’s Microsoft Graph profile (id, displayName, mail, jobTitle, etc.). | _(none)_ | `GET /me` |
|
|
109
|
-
| `get-my-profile-photo` | Download the signed-in user’s profile photo (largest available size). Returned as a base64 envelope so the binary survives JSON output. | _(none)_ | `GET /me/photo/$value` |
|
|
110
|
-
|
|
111
|
-
### Calendar
|
|
112
|
-
|
|
113
|
-
| Command | Description | Required params | Graph endpoint |
|
|
114
|
-
|---------|-------------|-----------------|----------------|
|
|
115
|
-
| `get-calendar-event` | Fetch a single calendar event by ID from the signed-in user’s default calendar. | `--event-id` | `GET /me/events/{event-id}` |
|
|
116
|
-
| `get-calendar-view` | List the signed-in user’s default-calendar events with recurrence expanded into individual occurrences in a date range. Both ISO date-time params are required by Graph. | `--start-date-time`, `--end-date-time` | `GET /me/calendarView?startDateTime={start-date-time}&endDateTime={end-date-time}` |
|
|
117
|
-
| `get-specific-calendar-event` | Fetch a single calendar event by ID from a specific (non-default) calendar. | `--calendar-id`, `--event-id` | `GET /me/calendars/{calendar-id}/events/{event-id}` |
|
|
118
|
-
| `get-specific-calendar-view` | List the events in a specific (non-default) calendar with recurrence expanded into individual occurrences in a date range. Both ISO date-time params are required by Graph. | `--calendar-id`, `--start-date-time`, `--end-date-time` | `GET /me/calendars/{calendar-id}/calendarView?startDateTime={start-date-time}&endDateTime={end-date-time}` |
|
|
119
|
-
| `list-calendar-event-instances` | List the individual occurrences of a recurring calendar event over a date range. Both ISO date-time params are required by Graph. | `--calendar-id`, `--event-id`, `--start-date-time`, `--end-date-time` | `GET /me/calendars/{calendar-id}/events/{event-id}/instances?startDateTime={start-date-time}&endDateTime={end-date-time}` |
|
|
120
|
-
| `list-calendar-events` | List the events in the signed-in user’s default calendar (does not expand recurrences). | _(none)_ | `GET /me/events` |
|
|
121
|
-
| `list-calendar-events-delta` | Get the incremental change set (added / modified / deleted events) for the signed-in user’s default calendar. Use the `@odata.deltaLink` from a previous response to resume. | _(none)_ | `GET /me/events/delta()` |
|
|
122
|
-
| `list-calendar-view-delta` | Get the first page of the incremental change set of expanded calendar-view occurrences over a date range. Subsequent pages: feed the returned `@odata.nextLink` to `next-page`; resume later via the `@odata.deltaLink`. | `--start-date-time`, `--end-date-time` | `GET /me/calendarView/delta()?startDateTime={start-date-time}&endDateTime={end-date-time}` |
|
|
123
|
-
| `list-calendars` | List the calendars in the signed-in user’s mailbox (default + secondary calendars + shared calendars). | _(none)_ | `GET /me/calendars` |
|
|
124
|
-
| `list-specific-calendar-events` | List the events in a specific (non-default) calendar (does not expand recurrences). | `--calendar-id` | `GET /me/calendars/{calendar-id}/events` |
|
|
125
|
-
|
|
126
|
-
### Chats
|
|
127
|
-
|
|
128
|
-
| Command | Description | Required params | Graph endpoint |
|
|
129
|
-
|---------|-------------|-----------------|----------------|
|
|
130
|
-
| `list-chat-members` | List the members of a single Microsoft Teams chat. | `--chat-id` | `GET /chats/{chat-id}/members` |
|
|
131
|
-
|
|
132
|
-
### Teams
|
|
133
|
-
|
|
134
|
-
| Command | Description | Required params | Graph endpoint |
|
|
135
|
-
|---------|-------------|-----------------|----------------|
|
|
136
|
-
| `get-team` | Get the metadata of a single Microsoft Team (display name, settings, member-settings, owner group). | `--team-id` | `GET /teams/{team-id}` |
|
|
137
|
-
| `get-team-channel` | Get the metadata of a single channel inside a Microsoft Team. | `--team-id`, `--channel-id` | `GET /teams/{team-id}/channels/{channel-id}` |
|
|
138
|
-
| `list-joined-teams` | List the Microsoft Teams the signed-in user is a member of. | _(none)_ | `GET /me/joinedTeams` |
|
|
139
|
-
| `list-team-channels` | List the channels (standard, private, shared) inside a single Microsoft Team. | `--team-id` | `GET /teams/{team-id}/channels` |
|
|
140
|
-
|
|
141
|
-
### Meta / Pagination
|
|
142
|
-
|
|
143
|
-
| Command | Description | Required params | Graph endpoint |
|
|
144
|
-
|---------|-------------|-----------------|----------------|
|
|
145
|
-
| `next-page` | Fetch the next page of a paginated Graph response. Pass the `@odata.nextLink` value returned by any list / search / delta command to walk pagination yourself. | `--url` | `GET {url}` |
|
|
146
|
-
|
|
147
|
-
<!-- AUTO-GENERATED-COMMANDS:END -->
|
|
148
|
-
## Install
|
|
149
|
-
|
|
150
|
-
Requires Node ≥20 **or** Bun ≥1.0 on the user's machine. Works on Windows, macOS, and Linux.
|
|
3
|
+
**A Microsoft Graph CLI built for LLMs.** 165 read-only commands across Mail, Calendar, OneDrive, SharePoint, Excel, Teams chats, Planner / To-Do, OneNote, and directory. Sign in once with your Microsoft 365 account — no Azure app registration, no admin consent, no client secrets.
|
|
151
4
|
|
|
152
5
|
```bash
|
|
153
|
-
npm i -g ask-marcel-office-cli
|
|
154
|
-
#
|
|
155
|
-
|
|
6
|
+
npm i -g ask-marcel-office-cli
|
|
7
|
+
ask-marcel login # browser opens once, token cached
|
|
8
|
+
ask-marcel my-quick-context # who am I + my IDs, in one round trip
|
|
9
|
+
ask-marcel list-mail-messages --top 5
|
|
156
10
|
```
|
|
157
11
|
|
|
158
|
-
|
|
12
|
+
---
|
|
159
13
|
|
|
160
|
-
##
|
|
14
|
+
## Why it exists
|
|
15
|
+
|
|
16
|
+
LLM tool-loops keep hitting the same three walls with Microsoft Graph:
|
|
17
|
+
|
|
18
|
+
1. **Auth is a project.** Register an app, get tenant-admin consent, manage secrets, refresh tokens — before the first API call.
|
|
19
|
+
2. **Default payloads are tuned for backend services, not context windows.** Listing endpoints return every field on every item, used-range Excel calls return four redundant 2D arrays, attachment endpoints inline base64 by default. An agent that reads "what's in my inbox" without trimming burns its budget on metadata it never needed.
|
|
20
|
+
3. **Errors are opaque.** `BadRequest: Invalid filter clause` doesn't tell a model what to fix.
|
|
21
|
+
|
|
22
|
+
`ask-marcel` fixes all three at the CLI layer, so the model just calls commands and reads back-pressure-friendly responses.
|
|
23
|
+
|
|
24
|
+
## What you get
|
|
25
|
+
|
|
26
|
+
### Read-only by design
|
|
27
|
+
|
|
28
|
+
**This is the most important property.** 164 GET endpoints + 1 POST (search). No `send-mail`, no `create-event`, no `upload-file`, no `delete-anything`. A hallucinated command can't break anything — the worst case is a 404. Safe default for autonomous agents, MCP servers, and "let Claude poke around my mailbox" sessions where you can't fully review every tool call.
|
|
29
|
+
|
|
30
|
+
### One call gets the full email context
|
|
31
|
+
|
|
32
|
+
A typical "read this email" loop in raw Graph: GET the message → GET the attachments list → GET each attachment's bytes → scan the body HTML for `sharepoint.com` URLs → resolve each URL to a driveItem → GET each driveItem. Six round-trips minimum, plus HTML-to-text conversion the LLM has to do itself.
|
|
33
|
+
|
|
34
|
+
`convert-mail-to-markdown` collapses that into one call:
|
|
35
|
+
|
|
36
|
+
- Body rendered as markdown (turndown pipeline)
|
|
37
|
+
- Inline images embedded as base64 `data:` URIs (size-capped per image — opt out with `--inline-images false` to keep raw `cid:` refs)
|
|
38
|
+
- File attachments listed below the body with id + name + size, ready for follow-up calls
|
|
39
|
+
- Pair with `extract-sharepoint-links-in-mail` to resolve every SharePoint URL in the body to its driveItem in parallel (capped at 25 unique URLs per call)
|
|
40
|
+
|
|
41
|
+
### Office docs → markdown or PDF on the fly
|
|
42
|
+
|
|
43
|
+
Feed any Office-shaped file (docx, xlsx, pptx, csv, rtf, odt, …) into the local conversion pipeline OR through Graph's `?format=pdf` when slide layout and images matter:
|
|
44
|
+
|
|
45
|
+
- `download-drive-item-as-markdown` — docx via mammoth (with inline images as data URIs), xlsx as one markdown table per sheet, csv as a table, plain-text passthrough
|
|
46
|
+
- `download-drive-item-as-pdf` — Graph PDF conversion for anything it supports (preserves slide layout, images, charts — the right call for pptx and image-heavy docs)
|
|
47
|
+
- `convert-mail-attachment-to-markdown` / `convert-mail-attachment-to-pdf` — same pipelines but starting from an email attachment
|
|
48
|
+
|
|
49
|
+
The CLI follows any SharePoint media-transform redirect internally, so the LLM never has to fetch an external URL.
|
|
50
|
+
|
|
51
|
+
### Browser-OAuth at first launch
|
|
52
|
+
|
|
53
|
+
No Azure app, no tenant admin. The CLI captures the same token the Teams web client uses — works for any Microsoft 365 account, personal or enterprise.
|
|
54
|
+
|
|
55
|
+
### Stable error envelope with actionable hints
|
|
56
|
+
|
|
57
|
+
Every failure — Graph, CLI parser, Zod validation, substrate — comes back as `{ok: false, error, errorCode?, hint?, source}`. The `hint` field tells the model *what to do next* (e.g. "string literals MUST use single quotes; embed one by doubling it") and `source` tells it where the failure came from. Curated rules for 20+ recurring Graph errors plus cross-resolver pointers (passed a Teams URL to `resolve-mail-link`? Hint says "re-run with `resolve-teams-link`").
|
|
58
|
+
|
|
59
|
+
### Lean responses
|
|
60
|
+
|
|
61
|
+
Listings ship with hand-tuned `--select` defaults — a mail listing returns id, subject, from, to, cc, dates, read-state, importance, bodyPreview rather than every field on every message. `get-excel-used-range` returns the `values` array instead of the four 2D arrays Graph emits. Opt out per call with `--full true`, or override with your own `--select id,subject,body`.
|
|
62
|
+
|
|
63
|
+
### Saves big binaries to disk so they never hit the model's context
|
|
64
|
+
|
|
65
|
+
A typical conversion command returns multi-MB PDF bytes. Sending 5 MB of base64 through stdout would blow most context windows AND quadruple the token bill.
|
|
66
|
+
|
|
67
|
+
Two flag patterns avoid the round-trip:
|
|
68
|
+
|
|
69
|
+
- **`--output-path /path/to/file.pdf`** — the CLI decodes the bytes, writes them to disk, and replaces `base64: "..."` in the envelope with `savedTo: "/path/to/file.pdf"`. The LLM sees a 3-line confirmation instead of a 7-million-character payload. Works on every command that returns binary or text content; rejected with a clear error on plain-JSON commands so a misapplied flag is never silent.
|
|
70
|
+
- **No flag, text mode** — binary commands print a one-line summary (`binary: application/pdf, 4837291 bytes — use --output-path to save`) instead of spilling base64 to stdout. The LLM sees a hint without ever pulling the bytes.
|
|
71
|
+
|
|
72
|
+
### Relative dates on calendar windows
|
|
73
|
+
|
|
74
|
+
`--start-date-time "start-of-week" --end-date-time "+7d"`. No timestamp math before answering "what's on my calendar this week".
|
|
75
|
+
|
|
76
|
+
## 30-second quickstart
|
|
161
77
|
|
|
162
78
|
```bash
|
|
79
|
+
# install (Bun ≥1.0 or Node ≥20)
|
|
80
|
+
npm i -g ask-marcel-office-cli
|
|
81
|
+
|
|
163
82
|
# authenticate (cached → refresh → browser fallback)
|
|
164
83
|
ask-marcel login
|
|
165
84
|
|
|
166
|
-
#
|
|
85
|
+
# everything else is read-only and discoverable from --help
|
|
167
86
|
ask-marcel list-drives
|
|
87
|
+
ask-marcel search-onedrive-files --drive-id "b!abc..." --query "Q3 budget"
|
|
88
|
+
ask-marcel convert-mail-to-markdown --message-id "AAMkAD..."
|
|
89
|
+
ask-marcel list-calendar-view --start-date-time today --end-date-time +7d
|
|
90
|
+
ask-marcel convert-mail-attachment-to-pdf \
|
|
91
|
+
--message-id "AAMkAD..." --attachment-id "AAMkAD...attach1" \
|
|
92
|
+
--output-path /tmp/deck.pdf
|
|
93
|
+
```
|
|
168
94
|
|
|
169
|
-
|
|
170
|
-
ask-marcel search-onedrive-files --drive-id abc123 --query "report"
|
|
95
|
+
## Asking the CLI what it can do
|
|
171
96
|
|
|
172
|
-
|
|
173
|
-
ask-marcel list-excel-table-rows --drive-id abc123 --item-id xyz789 --table-id table1
|
|
97
|
+
Five discovery surfaces, each tuned for a different audience and token budget:
|
|
174
98
|
|
|
175
|
-
|
|
176
|
-
|
|
99
|
+
| When you want | Run | Returns |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| Help with a single command | `ask-marcel <command> --help` | Required flags, optional flags, an example, pagination notes |
|
|
102
|
+
| A scan of every command | `ask-marcel --help` | One-sentence summary per command, grouped by category |
|
|
103
|
+
| The slim LLM-friendly index | `ask-marcel help-json --terse` | JSON manifest with heavy fields (options, response shape) stripped — best first-call for an agent meeting the CLI for the first time |
|
|
104
|
+
| The slim index for one domain | `ask-marcel help-json --terse --category mail` | Same as above, filtered to one of 12 categories — keeps the response tiny when the agent already knows the domain |
|
|
105
|
+
| Rich docs for one command | `ask-marcel docs <command>` | Full Markdown to stdout (response shape, examples, the underlying Graph endpoint, Microsoft Learn link) |
|
|
177
106
|
|
|
178
|
-
|
|
179
|
-
ask-marcel list-sharepoint-site-lists --site-id contoso.sharepoint.com,1234-5678
|
|
107
|
+
Pair `help-json --terse --category <name>` with `docs <command>` for the canonical agent loop: scan the category, pick a command, fetch its full docs, then call it.
|
|
180
108
|
|
|
181
|
-
|
|
182
|
-
ask-marcel update
|
|
109
|
+
## Use it from Claude Code, Cursor, Cline, or any tool-calling LLM
|
|
183
110
|
|
|
184
|
-
|
|
185
|
-
ask-marcel logout
|
|
111
|
+
Most agents already know how to read JSON from stdout. Two patterns work:
|
|
186
112
|
|
|
187
|
-
|
|
188
|
-
ask-marcel --help
|
|
189
|
-
```
|
|
113
|
+
**1. Drop in as a shell tool** — the agent learns the manifest, then runs `ask-marcel <command> --output json`. The slim defaults + structured error hints mean it can self-recover from typos.
|
|
190
114
|
|
|
191
|
-
|
|
115
|
+
**2. Embed as a library** — every command is exported. Compose it inside your own MCP server, Claude Agent, or LangChain tool:
|
|
192
116
|
|
|
193
|
-
|
|
117
|
+
```ts
|
|
118
|
+
import { commands, buildDeps } from 'ask-marcel-office-cli';
|
|
119
|
+
|
|
120
|
+
const { graph } = buildDeps();
|
|
121
|
+
const result = await commands['list-mail-messages'].execute(graph, { top: '10' });
|
|
122
|
+
if (result.ok) {
|
|
123
|
+
// result.value is the Graph payload — typed Result<unknown, GraphError>
|
|
124
|
+
}
|
|
125
|
+
```
|
|
194
126
|
|
|
195
|
-
|
|
127
|
+
### Auth — two paths
|
|
196
128
|
|
|
197
|
-
|
|
129
|
+
**Most users — use the built-in browser-OAuth ladder:**
|
|
198
130
|
|
|
199
131
|
```ts
|
|
200
|
-
import {
|
|
132
|
+
import { buildDeps } from 'ask-marcel-office-cli';
|
|
201
133
|
|
|
202
|
-
// option 1 — full ladder with built-in OAuth and file cache
|
|
203
134
|
const { graph } = buildDeps();
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
// option 2 — bring your own AuthManager / token
|
|
208
|
-
const graph = createGraphClient({
|
|
209
|
-
getAccessToken: async () => ({ ok: true, value: process.env.MS_GRAPH_TOKEN as never }),
|
|
210
|
-
logout: async () => ({ ok: true, value: undefined }),
|
|
211
|
-
});
|
|
212
|
-
const me = await commands['get-current-user'].execute(graph, {});
|
|
135
|
+
// First call triggers cache → refresh → headed-Chromium fallback automatically.
|
|
136
|
+
// Tokens cached at ~/.ask-marcel/token-cache.json for subsequent calls.
|
|
213
137
|
```
|
|
214
138
|
|
|
215
|
-
|
|
139
|
+
**Agents / CI / MCP servers — bring your own token:**
|
|
216
140
|
|
|
217
|
-
|
|
141
|
+
```ts
|
|
142
|
+
import { createGraphClient } from 'ask-marcel-office-cli';
|
|
218
143
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
144
|
+
const graph = createGraphClient({
|
|
145
|
+
getAccessToken: async () => ({
|
|
146
|
+
ok: true,
|
|
147
|
+
value: await fetchTokenFromYourVault(),
|
|
148
|
+
}),
|
|
149
|
+
logout: async () => ({ ok: true, value: undefined }),
|
|
150
|
+
});
|
|
226
151
|
```
|
|
227
152
|
|
|
228
|
-
|
|
229
|
-
- **Client ID**: `5e3ce6c0-2b1f-4285-8d4b-75ee78787346` (Teams Web)
|
|
230
|
-
- **Scopes**: `https://graph.microsoft.com/.default openid profile offline_access`
|
|
231
|
-
- **Token cache**: `~/.ask-marcel/token-cache.json` (overridable via `BuildDepsConfig.cachePath`)
|
|
232
|
-
- **Browser profile**: `~/.ask-marcel/browser-profile` (overridable via `ASKMARCEL_BROWSER_PROFILE`)
|
|
233
|
-
- **Output**: Compact JSON via `JSON.stringify` — no indentation, optimised for LLM token efficiency
|
|
153
|
+
The `AuthManager` interface is two async methods that return `Result<T, AuthError>`. Plug in any token source — Azure Managed Identity, a secrets vault, an on-behalf-of flow, hand-pasted JWTs in tests. The Graph client doesn't care where the token came from.
|
|
234
154
|
|
|
235
|
-
##
|
|
155
|
+
## Deep docs
|
|
236
156
|
|
|
237
|
-
|
|
157
|
+
- **[All 165 commands](docs/COMMANDS.md)** — per-category tables with required params + Graph endpoint
|
|
158
|
+
- **[Usage guide](docs/USAGE.md)** — output formats, OData passthrough, `--output-path`, pagination, library API, architecture, configuration, quality gates
|
|
159
|
+
- **[Machine-readable manifest](docs/commands.json)** — JSON for programmatic discovery (LLM tool-loops, IDE plugins, MCP servers); also importable via `import manifest from 'ask-marcel-office-cli/commands.json'`
|
|
238
160
|
|
|
239
|
-
|
|
240
|
-
|---|---|---|
|
|
241
|
-
| `ASKMARCEL_LOG_LEVEL` | Winston logger; all output goes to **stderr** (stdout reserved for command JSON). Namespaced so a generic `LOG_LEVEL` exported by another tool in your shell does not leak into ours. | `error` (use `info` or `debug` for troubleshooting) |
|
|
242
|
-
| `HOME` / `USERPROFILE` | Default cache and browser-profile paths | _(required)_ |
|
|
243
|
-
| `ASKMARCEL_BROWSER_PROFILE` | Override Playwright user-data-dir | _(none)_ |
|
|
161
|
+
## Roadmap
|
|
244
162
|
|
|
245
|
-
|
|
163
|
+
Read-only stays the default forever. The list below is additive coverage and convenience — concrete next steps, ordered by how often they come up in real LLM workflows:
|
|
246
164
|
|
|
247
|
-
|
|
165
|
+
- **Zip archive support** — extract a `.zip` from an email attachment or OneDrive item and run every contained file through the right conversion pipeline (markdown or PDF), so an agent reading "the project handover archive" doesn't have to shell out to `unzip`.
|
|
166
|
+
- **SharePoint links inside documents** — today `extract-sharepoint-links-in-mail` finds and resolves every `sharepoint.com` URL in an email body; the same pass for inline links in docx/xlsx/pptx would close the loop on "follow every reference in this document".
|
|
167
|
+
- **Bulk folder conversion** — `convert-folder --drive-id … --item-id <folder> --format markdown` walks a folder and converts every Office file in one call, returning the combined markdown (or writing per-file outputs to a directory via `--output-path`).
|
|
168
|
+
- **OneNote end-to-end markdown** — OneNote page reads currently return raw HTML; chaining the turndown pipeline (same one `convert-mail-to-markdown` uses) would give parity with the docx route.
|
|
169
|
+
- **PowerPoint as slide images** — for vision-capable LLMs, render each pptx slide as a PNG alongside the existing PDF route so the model can reason about layout + diagrams without going through PDF parsing.
|
|
170
|
+
- **Calendar meeting attachments** — `/events/{id}/attachments` isn't exposed yet; would pair with the existing `convert-mail-attachment-to-*` shape so "summarize the deck attached to my 3pm" is a single call.
|
|
171
|
+
- **Multi-tenant auth profiles** — `ask-marcel login --profile work` / `--profile personal` with separate token caches at `~/.ask-marcel/<profile>/`, for consultants and contractors who routinely switch tenants.
|
|
172
|
+
- **Streaming pagination output** — write each page to stdout as it arrives instead of accumulating, so long delta walks don't hold gigabytes in memory and an agent can start processing page 1 while page 2 is in flight.
|
|
173
|
+
- **Excel charts as PNG** — `list-excel-worksheet-charts` already returns chart metadata; add `get-excel-chart-image` that renders the chart as a base64 PNG via Graph's `.../charts/{id}/image()` endpoint so vision-capable models can read the chart, not just its title.
|
|
174
|
+
- **Yammer / Viva Engage** — community posts, threads, and replies. Currently unscoped on the Teams web-client token, so this would need a scope investigation first.
|
|
175
|
+
- **Federated tenant search expansion** — `microsoft-search-query` exists but covers a narrow entity set; expanding to people, sites, lists, and chat messages would unify discovery across all of M365 behind one search call.
|
|
176
|
+
- **Quoted-text stripping in `convert-mail-to-markdown`** — collapse "On Tuesday Alice wrote..." reply chains so long threads stop blowing the context budget on duplicated quoted content.
|
|
177
|
+
- **`--diff` flag on `download-drive-item-version` markdown** — render the markdown diff between two historical versions of the same file (e.g. "what changed in the spec last week"), so an agent can answer revision questions without manually comparing two long markdown blobs.
|
|
178
|
+
- **Full-fidelity document context** — extract every piece of written information in a document: reviewer comments, threaded comments, slide notes, revision marks, descriptions, custom metadata, and sensitivity labels — folded into the markdown output so an LLM reads the whole story of a document, not just its body text.
|
|
179
|
+
- **OCR for images and image-only PDFs** — pipe images (jpg/png attachments, inline email images) and scanned PDFs through a local OCR pass, returning extracted text as markdown. Closes the loop on screenshots, scanned receipts, and image-only attachments that today come back as opaque bytes.
|
|
248
180
|
|
|
249
|
-
|
|
250
|
-
bun test # full suite
|
|
251
|
-
bun run lint # ESLint (0 warnings, 0 errors)
|
|
252
|
-
bun run typecheck # tsc --noEmit
|
|
253
|
-
bun run coverage # per-tier gates (100% on every tier: domain, use-cases, infra, composition, presenter)
|
|
254
|
-
bun run mutate:changed # mutation testing on changed domain/use-case files (>90% kill threshold)
|
|
255
|
-
```
|
|
181
|
+
Suggestions, requests, and pull requests welcome — see the [issues page](https://github.com/vdelacou/ask-marcel-office-cli/issues).
|
|
256
182
|
|
|
257
|
-
|
|
183
|
+
## Built with
|
|
258
184
|
|
|
259
|
-
|
|
185
|
+
- **Bun + TypeScript** — single binary install, Node ≥20 fallback. `Result<T, E>` at every IO boundary, branded value-object types at trust boundaries, classicist outside-in TDD, zero lint warnings, 100% coverage on every tier.
|
|
186
|
+
- **Microsoft Graph v1.0** — the public API surface, no beta endpoints in production code.
|
|
187
|
+
- **Playwright** — headed Chromium for the first-launch browser-OAuth dance.
|
|
260
188
|
|
|
261
|
-
|
|
262
|
-
git config core.hooksPath .githooks
|
|
263
|
-
```
|
|
189
|
+
## License
|
|
264
190
|
|
|
265
|
-
|
|
191
|
+
MIT © Vincent Delacourt
|