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/docs/USAGE.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Usage guide
|
|
2
|
+
|
|
3
|
+
Everything beyond "install and call a command" — output formats, OData passthrough, writing bytes to disk, pagination, the library API, architecture, configuration, and the quality gates the project ships under.
|
|
4
|
+
|
|
5
|
+
For the command list see [`COMMANDS.md`](COMMANDS.md). For programmatic discovery see [`commands.json`](commands.json).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## CLI basics
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# install (Bun ≥1.0 or Node ≥20, Windows / macOS / Linux)
|
|
13
|
+
npm i -g ask-marcel-office-cli
|
|
14
|
+
# — or —
|
|
15
|
+
bun add -g ask-marcel-office-cli
|
|
16
|
+
|
|
17
|
+
# authenticate (cached → refresh → browser fallback)
|
|
18
|
+
ask-marcel login
|
|
19
|
+
|
|
20
|
+
# the rest is discoverable
|
|
21
|
+
ask-marcel --help # ~28 KB, one-sentence summaries
|
|
22
|
+
ask-marcel help-json --terse --category mail # ~12 KB JSON for one category
|
|
23
|
+
ask-marcel docs list-mail-messages # full per-command Markdown
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`ask-marcel update` auto-detects whether the CLI was installed via npm or bun (based on the bin path) and reinstalls globally with the matching tool. From a clone you can keep using `bun run src/main.ts <command>` directly.
|
|
27
|
+
|
|
28
|
+
The first launch prints a one-time notice if a newer version is on npm.
|
|
29
|
+
|
|
30
|
+
## Output formats — `--output text` (default) vs `--output json`
|
|
31
|
+
|
|
32
|
+
Every command writes its output as a single document to **stdout** (success or error — there is no stderr output). `process.exitCode` is `0` on success and `1` on any failure. Pick the format with the global `--output <text|json>` flag.
|
|
33
|
+
|
|
34
|
+
### Text (default, LLM-readable)
|
|
35
|
+
|
|
36
|
+
YAML-ish `key: value` lines, generally smaller than the JSON envelope on long listings (the win grows with page size and shrinks toward parity on small projected pages — a 3-message page is ~3.3 KB in either format). Errors render as `error: <message>` followed by `hint:` and `source:` lines so an LLM can match the line shape without parsing JSON. Designed for LLMs reading and summarising; not for piping into other tools.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
$ ask-marcel get-current-user
|
|
40
|
+
id: 0c1d2e3f-…
|
|
41
|
+
displayName: Vincent Delacourt
|
|
42
|
+
mail: vincent@example.com
|
|
43
|
+
|
|
44
|
+
$ ask-marcel list-mail-folder-messages --mail-folder-id inbox --top 2
|
|
45
|
+
id: AAMkAGI2…
|
|
46
|
+
subject: Re: Q2 planning
|
|
47
|
+
from: alice@example.com
|
|
48
|
+
|
|
49
|
+
id: AAMkAGI3…
|
|
50
|
+
subject: Lunch?
|
|
51
|
+
from: bob@example.com
|
|
52
|
+
|
|
53
|
+
--- next: https://graph.microsoft.com/v1.0/me/messages?$skip=2
|
|
54
|
+
|
|
55
|
+
$ ask-marcel get-mail-message --message-id "bad-id"
|
|
56
|
+
error: ErrorInvalidIdMalformed: Id is malformed.
|
|
57
|
+
hint: The ID you passed isn't valid for this endpoint. Source IDs from a sibling `list-*` command (e.g. `list-mail-messages`, `list-folder-files`, `list-chats`) — never construct them by hand.
|
|
58
|
+
source: graph
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Pagination cursors (`nextLink`, `deltaLink`) and `count` render as a single footer line prefixed with `---` and separated by middle dots. Empty listings render as `(no items)` so silence is never ambiguous. Binary commands (PDFs etc.) print `binary: <contentType>, <size> bytes — use --output-path to save` instead of a base64 blob.
|
|
62
|
+
|
|
63
|
+
### JSON (`--output json`, opt-in for tool-chaining)
|
|
64
|
+
|
|
65
|
+
The stable `{ok, data, nextLink?, deltaLink?, count?}` envelope, unambiguous for `jq` / script extraction and chaining one command's output into another's `--filter` / `--message-id`.
|
|
66
|
+
|
|
67
|
+
```jsonc
|
|
68
|
+
// Success
|
|
69
|
+
{
|
|
70
|
+
"ok": true,
|
|
71
|
+
"data": { /* the Graph payload, or whatever the use-case returned */ },
|
|
72
|
+
"nextLink": "https://graph.microsoft.com/v1.0/me/messages?$skip=10",
|
|
73
|
+
"deltaLink": "https://graph.microsoft.com/v1.0/me/events/delta?$deltatoken=ABC",
|
|
74
|
+
"count": 42
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Error — stable shape across CLI-validation, Commander parser, and Graph failures
|
|
78
|
+
{
|
|
79
|
+
"ok": false,
|
|
80
|
+
"error": "ErrorInvalidIdMalformed: Id is malformed.",
|
|
81
|
+
"errorCode": "ErrorInvalidIdMalformed",
|
|
82
|
+
"hint": "The ID you passed isn't valid for this endpoint. Source IDs from a sibling `list-*` command…",
|
|
83
|
+
"source": "graph"
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`@odata.nextLink`, `@odata.deltaLink`, and `@odata.count` from the Graph payload are lifted to the envelope's top level and removed from `data`, so consumers don't have to know the OData spelling. **Always check the top-level `nextLink` (and `deltaLink` for `*-delta` commands) — never reach into `data["@odata.nextLink"]`; it's been moved.** This applies uniformly across every paginated `list-*` / `search-*` / `*-delta` command.
|
|
88
|
+
|
|
89
|
+
`source` is one of `graph` | `substrate` | `cli` | `validation`. `hint` is present when a curated rule matched the error code or message; the envelope shape is `{ok, error, errorCode?, hint?, source}` where only `hint` is conditional.
|
|
90
|
+
|
|
91
|
+
## OData query passthrough
|
|
92
|
+
|
|
93
|
+
Most `list-*`, `search-*`, and `*-delta` commands accept the standard OData query parameters as optional flags. Use them to shrink large responses on the fly — particularly important for context-window-bound LLM consumers:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
ask-marcel list-mail-messages --top 5 --select id,subject,from,receivedDateTime
|
|
97
|
+
ask-marcel list-recent-files --filter "name eq 'budget.xlsx'" --orderby lastModifiedDateTime desc
|
|
98
|
+
ask-marcel list-folder-files --drive-id b!abc --item-id 01DEF --select id,name --top 10
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The canonical set is `--top <n>`, `--skip <n>`, `--select <csv>`, `--filter <kql>`, `--orderby <kql>`, `--expand <nav>`. `--top` is capped at 1000 with a clear validation error (Graph silently truncates beyond that on every endpoint). **The CLI advertises only the flags the underlying Graph endpoint honors — flags Graph silently rejects or ignores are dropped from the option set, so the manifest never lies.**
|
|
102
|
+
|
|
103
|
+
Narrower variants (a sample — see each command's `--help` for the exact list):
|
|
104
|
+
|
|
105
|
+
- **No `--skip`** on endpoints Graph rejects it (paginate via `nextLink` → `next-page` instead).
|
|
106
|
+
- **`--filter` / `--orderby` dropped** on Excel listings (Graph silently ignores them).
|
|
107
|
+
- **`--select` only** on Planner listings and `list-team-installed-apps` (server-pinned `$expand`).
|
|
108
|
+
- **No OData at all** on `list-shared-with-me`, `list-mail-rules`, `list-outlook-categories`, `get-mailbox-settings` — Graph silently ignores every passthrough; slice client-side.
|
|
109
|
+
- **`--top` only** on the delta endpoints `list-calendar-events-delta` and `list-calendar-view-delta` (translated internally to `Prefer: odata.maxpagesize`; `$top` as a query parameter is rejected by Graph).
|
|
110
|
+
|
|
111
|
+
`list-todo-tasks` rewrites Graph's opaque `RequestBroker--ParseUri` to a clear hint when `--select` / `--orderby` trips the title-quirk; `list-calendar-event-instances` rewrites `ExpandSeries can only be performed against a series` to a pointer at `--filter "type eq 'seriesMaster'"`; `list-my-direct-reports` auto-injects the `ConsistencyLevel: eventual` header Graph requires for `--orderby` on directory endpoints. `get-excel-range` caps the in-flight range at 100 000 cells to prevent runaway responses.
|
|
112
|
+
|
|
113
|
+
## Relative dates on calendar-view commands
|
|
114
|
+
|
|
115
|
+
Every `--start-date-time` / `--end-date-time` flag on the calendar-view family (`list-calendar-view`, `list-calendar-view-delta`, `list-specific-calendar-view`, `list-shared-calendar-view`, `list-group-calendar-view`, `list-calendar-event-instances`) accepts strict ISO 8601 (`2026-04-01T00:00:00Z`) AND a relative vocabulary, so an LLM doesn't have to compute timestamps before answering "what's on my calendar this week":
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
ask-marcel list-calendar-view --start-date-time "start-of-week" --end-date-time "end-of-week"
|
|
119
|
+
ask-marcel list-calendar-view --start-date-time "today" --end-date-time "+7d"
|
|
120
|
+
ask-marcel list-calendar-view --start-date-time "monday" --end-date-time "next-monday"
|
|
121
|
+
ask-marcel list-calendar-view --start-date-time "start-of-month" --end-date-time "end-of-month"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Accepted shapes (UTC, week starts Monday): strict ISO; date-only (`2026-04-01` → midnight UTC); past offsets `7d` / `1w` / `2h` / `30m`; future offsets `+7d` / `+1w`; named `now` / `today` / `yesterday` / `tomorrow`; weekday names (`monday`-`sunday` — most-recent occurrence including today); `last-<weekday>` / `next-<weekday>`; boundary anchors `start-of-week|month|year`, `end-of-week|month|year`. An unrecognised input returns a structured validation error listing every accepted shape — no second round-trip needed.
|
|
125
|
+
|
|
126
|
+
## Writing bytes to disk (`--output-path`)
|
|
127
|
+
|
|
128
|
+
Every download / convert command (PDF, image, raw bytes, MIME, OneNote HTML, the markdown converters) returns its bytes as `{ contentType, size, base64 }` (binary) or `{ contentType, size, text }` (text). In default text mode the binary variant prints `binary: <contentType>, <size> bytes — use --output-path to save` rather than spilling base64 to stdout. For multi-MB payloads — a 5 MB PDF round-tripped through stdout would blow most LLM context windows — pass the **global** `--output-path <path>` flag and the CLI lands the bytes locally:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
ask-marcel convert-mail-attachment-to-pdf \
|
|
132
|
+
--message-id "AAMkAD..." --attachment-id "AAMkAD...attach1" \
|
|
133
|
+
--output-path /tmp/deck.pdf
|
|
134
|
+
# Text mode:
|
|
135
|
+
# contentType: application/pdf
|
|
136
|
+
# size: 4837291
|
|
137
|
+
# savedTo: /tmp/deck.pdf
|
|
138
|
+
# JSON mode (--output json):
|
|
139
|
+
# {"ok":true,"data":{"contentType":"application/pdf","size":4837291,"savedTo":"/tmp/deck.pdf"}}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`--output-path` decodes `base64` (or writes `text`) to the path and replaces the inline field with `savedTo: <path>` in the response. Parent directories are created on demand. Applying the flag to a command that returns plain JSON (no `base64` / no `text` field — e.g. `get-current-user`) returns a clear `--output-path: <cmd> did not return inlined bytes …` error rather than silently writing nothing — a JSON-only command paired with this flag is almost certainly a mistake. The CLI follows any SharePoint media-transform redirect internally, so the LLM never has to fetch an external URL.
|
|
143
|
+
|
|
144
|
+
`help-json` and `docs <cmd>` also honour `--output-path` (the manifest JSON and per-command Markdown are written to disk and the envelope reports `savedTo`). Paths ending in `/` or `\` are rejected upfront with "must be a file path, not a directory" instead of leaking Node's `EISDIR`. When a `*-as-pdf` command falls back to raw source bytes (`passthrough: true`), the CLI refuses to write a `.pdf` extension — pick the source extension instead, so a corrupt save is impossible.
|
|
145
|
+
|
|
146
|
+
## Pagination
|
|
147
|
+
|
|
148
|
+
When a response contains a `nextLink` cursor, feed that URL back through `next-page` and repeat until the cursor is gone. In text mode the cursor is the value after `next:` in the `---` footer line; in JSON mode it's the top-level `nextLink` field. The script below uses `--output json` because `jq` needs the JSON envelope:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# page 1
|
|
152
|
+
ask-marcel --output json list-mail-folders > p1.json
|
|
153
|
+
|
|
154
|
+
# page 2..N — loop until nextLink is gone
|
|
155
|
+
next=$(jq -r '.nextLink // empty' p1.json)
|
|
156
|
+
while [ -n "$next" ]; do
|
|
157
|
+
ask-marcel --output json next-page --url "$next" > pN.json
|
|
158
|
+
next=$(jq -r '.nextLink // empty' pN.json)
|
|
159
|
+
done
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Every paginated command advertises this in three places: `ask-marcel <cmd> --help` prints a `Pagination:` line, `ask-marcel docs <cmd>` adds a `**Pagination:**` field, and [`docs/commands.json`](commands.json) ships `"pagination": true` on each entry so agents can detect it programmatically.
|
|
163
|
+
|
|
164
|
+
## Quick context
|
|
165
|
+
|
|
166
|
+
`ask-marcel my-quick-context` returns `{ user, primaryDriveId, inboxId, todoLists, primaryCalendarId }` in a single round trip — five Graph calls in parallel. Use it as the first call in any LLM session that needs per-user IDs to feed into other commands.
|
|
167
|
+
|
|
168
|
+
## Library API
|
|
169
|
+
|
|
170
|
+
The package exports a typed library API for embedding inside your own CLI, agent, or MCP server.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { commands, createGraphClient, buildDeps, type Result } from 'ask-marcel-office-cli';
|
|
174
|
+
|
|
175
|
+
// option 1 — full ladder with built-in OAuth and file cache
|
|
176
|
+
const { graph } = buildDeps();
|
|
177
|
+
const result = await commands['list-drives'].execute(graph, {});
|
|
178
|
+
if (result.ok) console.log(result.value);
|
|
179
|
+
|
|
180
|
+
// option 2 — bring your own AuthManager / token
|
|
181
|
+
const graph = createGraphClient({
|
|
182
|
+
getAccessToken: async () => ({ ok: true, value: process.env.MS_GRAPH_TOKEN as never }),
|
|
183
|
+
logout: async () => ({ ok: true, value: undefined }),
|
|
184
|
+
});
|
|
185
|
+
const me = await commands['get-current-user'].execute(graph, {});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The full export list (registry, factories, `Result`, branded types, ports) is in [`src/index.ts`](../src/index.ts). The machine-readable manifest is also available as a JSON subpath import:
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import manifest from 'ask-marcel-office-cli/commands.json' with { type: 'json' };
|
|
192
|
+
// manifest.commands is the full sorted entry list
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Architecture
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
src/
|
|
199
|
+
domain/ — Result<T,E>, branded value-object types (AccessToken, EnvVar), JWT utilities, format-error
|
|
200
|
+
infra/ — Auth recovery ladder (cache → refresh → Playwright browser), Graph API HTTP client, Winston logger
|
|
201
|
+
use-cases/ — Commands (schemas + execute functions), ports
|
|
202
|
+
composition/ — CLI wiring (Commander), dependency graph
|
|
203
|
+
presenter/ — Output formatting (text YAML-ish default + JSON envelope opt-in)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- **Auth**: Three-rung recovery ladder — file-based cached JWT → OAuth refresh_token exchange → Playwright browser intercepting Teams login
|
|
207
|
+
- **Client ID**: `5e3ce6c0-2b1f-4285-8d4b-75ee78787346` (Teams Web)
|
|
208
|
+
- **Scopes**: `https://graph.microsoft.com/.default openid profile offline_access`
|
|
209
|
+
- **Token cache**: `~/.ask-marcel/token-cache.json` (overridable via `BuildDepsConfig.cachePath`)
|
|
210
|
+
- **Browser profile**: `~/.ask-marcel/browser-profile` (overridable via `ASKMARCEL_BROWSER_PROFILE`)
|
|
211
|
+
- **Output**: YAML-ish text by default (LLM-readable, generally smaller than the JSON envelope on long listings, parity on small projected pages); compact JSON envelope via `--output json` for tool-chaining and `jq` pipelines
|
|
212
|
+
|
|
213
|
+
### Elevated token (historical-version downloads)
|
|
214
|
+
|
|
215
|
+
`download-drive-item-version --format <original|pdf|markdown>` needs a Graph token whose `appid` is on Microsoft's ODSP allow-list — the Teams web client token returns 403 with `logicalPermissionAccessDenied` against historical-version bytes.
|
|
216
|
+
|
|
217
|
+
Login captures a *second* Graph token from `https://m365.cloud.microsoft/search` whose first-party identity is M365ChatClient (`c0ab8ce9-e9a0-42e7-b064-33d422df41f1`) — an app on the ODSP allow-list. It is stored alongside the Teams token (`elevated_access_token` / `elevated_expires_on` fields in the cache) and used only by the historical-version command. Refresh path is re-capture via a brief Edge launch — the persistent profile cookies do silent SSO when fresh; if the federated IdP session has lapsed (e.g. Okta-fronted tenants), interactive sign-in completes inside the popup. If the elevated capture fails at login, every other command (including `list-chats` / `get-chat`, which use the regular Teams token) still works.
|
|
218
|
+
|
|
219
|
+
## Configuration
|
|
220
|
+
|
|
221
|
+
Environment variables read at composition time:
|
|
222
|
+
|
|
223
|
+
| Variable | Used by | Default |
|
|
224
|
+
|---|---|---|
|
|
225
|
+
| `ASKMARCEL_LOG_LEVEL` | Winston logger; all log output goes to **stderr** (stdout reserved for command output — text by default, JSON under `--output 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) |
|
|
226
|
+
| `HOME` / `USERPROFILE` | Default cache and browser-profile paths | _(required)_ |
|
|
227
|
+
| `ASKMARCEL_BROWSER_PROFILE` | Override Playwright user-data-dir | _(none)_ |
|
|
228
|
+
|
|
229
|
+
`HTTP_PROXY` / `HTTPS_PROXY` / `http_proxy` / `https_proxy` are stripped from the process environment immediately before launching Playwright (see `src/infra/browser-auth.ts`).
|
|
230
|
+
|
|
231
|
+
## Quality gates (atelier four-check loop)
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
bun test # full suite (2800+ tests)
|
|
235
|
+
bun run lint # ESLint (0 warnings, 0 errors)
|
|
236
|
+
bun run typecheck # tsc --noEmit
|
|
237
|
+
bun run coverage # per-tier gates (100% on every tier: domain, use-cases, infra, composition, presenter)
|
|
238
|
+
bun run mutate:changed # mutation testing on changed domain/use-case files (>90% kill threshold)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Pre-commit hook (atelier 8 gates)
|
|
242
|
+
|
|
243
|
+
The repo ships an 8-gate hook at `.githooks/pre-commit` (commit size → package.json → gitleaks → tests → strict lint → typecheck → coverage → mutation). Install once per clone:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
git config core.hooksPath .githooks
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Optional but recommended: install [gitleaks](https://github.com/gitleaks/gitleaks) (`brew install gitleaks`) to enable gate 3. The hook degrades gracefully if it's missing.
|