ask-marcel-office-cli 1.5.2 → 2.1.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +133 -3
  2. package/README.md +23 -59
  3. package/dist/cli.js +1757 -1766
  4. package/dist/commands.json +437 -275
  5. package/dist/composition/build-deps.d.ts +7 -8
  6. package/dist/composition/cli.d.ts +5 -4
  7. package/dist/domain/iso-datetime.d.ts +1 -1
  8. package/dist/index.js +1606 -1653
  9. package/dist/infra/auth.d.ts +37 -21
  10. package/dist/infra/browser-auth.d.ts +13 -12
  11. package/dist/infra/graph-client.d.ts +28 -2
  12. package/dist/presenter/error-hints.d.ts +9 -9
  13. package/dist/use-cases/commands/build-command.d.ts +1 -1
  14. package/dist/use-cases/commands/command-types.d.ts +5 -5
  15. package/dist/use-cases/commands/convert-local-file.d.ts +4 -0
  16. package/dist/use-cases/commands/create-forward-draft.d.ts +12 -0
  17. package/dist/use-cases/commands/create-reply-draft.d.ts +10 -0
  18. package/dist/use-cases/commands/docs.d.ts +1 -1
  19. package/dist/use-cases/commands/get-schedule.d.ts +11 -0
  20. package/dist/use-cases/commands/graph-scopes.d.ts +1 -1
  21. package/dist/use-cases/commands/image-extraction.d.ts +2 -1
  22. package/dist/use-cases/commands/iso-datetime-schema.d.ts +1 -1
  23. package/dist/use-cases/commands/login-status.d.ts +31 -0
  24. package/dist/use-cases/commands/login.d.ts +3 -1
  25. package/dist/use-cases/commands/markdown-pipeline.d.ts +5 -5
  26. package/dist/use-cases/commands/option-descriptions.d.ts +1 -1
  27. package/dist/use-cases/commands/output-path.d.ts +4 -4
  28. package/dist/use-cases/commands/parse-recipients.d.ts +14 -0
  29. package/dist/use-cases/commands/zip-archive-to-markdown.d.ts +4 -2
  30. package/dist/use-cases/ports/filesystem.d.ts +1 -1
  31. package/docs/COMMANDS.md +16 -13
  32. package/docs/USAGE.md +23 -23
  33. package/package.json +3 -4
  34. package/dist/composition/env.d.ts +0 -2
  35. package/dist/infra/system-browser-auth.d.ts +0 -35
  36. package/dist/infra/system-browser-loader.d.ts +0 -3
  37. package/dist/infra/token-callback-server.d.ts +0 -31
  38. package/docs/commands.json +0 -7676
package/CHANGELOG.md CHANGED
@@ -2,6 +2,134 @@
2
2
 
3
3
  All notable changes to `ask-marcel-office-cli` are documented here.
4
4
 
5
+ ## 2.1.0
6
+
7
+ ### Added
8
+
9
+ - **`create-forward-draft`** creates an UNSENT forward draft of an existing
10
+ message. `POST /me/messages/{id}/createForward` mints the draft (`FW:` subject,
11
+ quoted original) with your comment placed above the quote and the recipients
12
+ set, in one call (`Mail.ReadWrite`, already on the basic token).
13
+ `--to-recipients` is required (a forward with no recipient is not actionable);
14
+ `--cc-recipients` and a `--subject` override are optional. Like the other
15
+ mail-draft commands, it produces an UNSENT draft only; the CLI can never send.
16
+ This is the fourth and last write command, closing the "forward to the right
17
+ owner" gap that `create-reply-draft` (in-thread) could not.
18
+ - **`convert-local-file --include-images`** (a `.zip` only) also extracts every
19
+ archive entry's embedded images (docx/xlsx/pptx OOXML media parts, pdf page
20
+ images), so a screenshot pasted inside a zipped document is reachable in one
21
+ call.
22
+ - **`login` now reports all four cached tokens** (basic, elevated/M365, and the
23
+ two Teams-chat substrate tokens chatsvcagg / ic3) with each one's time-left and
24
+ refresh route, so running `login` while already signed in shows the full token
25
+ picture instead of a bare `{ status: "authenticated" }`. Each token is
26
+ `{ available, expiresInSeconds?, refresh: "automatic" | "interactive", reason? }`:
27
+ basic/chatsvcagg/ic3 refresh automatically from the cached refresh token; the
28
+ elevated token is `interactive` (re-captured only on a browser login).
29
+ - **`login --force`** ignores the cache and re-captures every token via the
30
+ browser in one pass — the only way to refresh the elevated token while the
31
+ basic token is still valid. The persistent browser profile is reused, so you
32
+ are usually not re-prompted for credentials.
33
+ - **`scopes-check` now reports the elevated (M365ChatClient) token** plus the two
34
+ Teams-chat substrate tokens (`chatsvcagg` / `ic3`), each in an
35
+ `{ available, expiresInSeconds? }` block, so a fresh process can pre-flight the
36
+ historical-version download / convert commands instead of discovering a 403
37
+ mid-run. The two substrate blocks are additive; the existing top-level fields
38
+ are unchanged.
39
+ - **Machine-readable `errorCode`s on more error paths** — the elevated /
40
+ substrate fail-fast (`secondary_token_unavailable`) and the client-side
41
+ unsupported-input rejections (`unsupported_image` / `unsupported_format` /
42
+ `unsupported_legacy_office` / `unsupported_document`), so an agent branches on
43
+ a stable code instead of substring-matching the message.
44
+
45
+ ### Fixed
46
+
47
+ - **`create-forward-draft` and `create-reply-draft` no longer drop the forwarded
48
+ / quoted body.** They set the comment via Graph's `comment` parameter on the
49
+ `createForward` / `createReplyAll` POST, which places it above the preserved
50
+ quote. The previous implementation PATCHed `body` with only the comment, which
51
+ **replaced** the whole draft body and dropped the entire forwarded original (a
52
+ forward went out with just the comment, no message). Caught by a live smoke
53
+ test; the fix is live-verified.
54
+
55
+ ### Changed
56
+
57
+ - The `parseRecipients` helper shared by the mail-draft write commands moved to
58
+ `parse-recipients.ts` (one definition, three call sites), with no behaviour
59
+ change.
60
+ - `scopes-check` `responseShape` corrected: `elevated.expiresInSeconds` is
61
+ omitted (the key is absent) when no elevated token is cached, not `null`.
62
+
63
+ ### Removed
64
+
65
+ - The `--body-content-type` flag on **`create-forward-draft` and
66
+ `create-reply-draft`** is removed. It never affected the quoted body (Graph
67
+ embeds the comment / reply as text above the quote), so it was a no-op on those
68
+ two commands. It remains on `create-mail-draft` and `update-mail-draft`, which
69
+ set the body directly.
70
+
71
+ ## 2.0.0
72
+
73
+ Breaking auth simplification, a repo-wide privacy scrub (including a rewrite of
74
+ the full git history), two new commands, and a headless self-heal for the Teams
75
+ chat-substrate tokens.
76
+
77
+ ### BREAKING
78
+
79
+ - **The CLI binary is renamed `ask-marcel` → `ask-marcel-office`** (matching the
80
+ package name; the bare `ask-marcel` name is freed for future use and no longer
81
+ ships as an alias). Update shell scripts, agent prompts, and skills that invoke
82
+ the old name. npm removes the stale `ask-marcel` bin link on upgrade; if one
83
+ lingers (e.g. bun global installs), delete it manually.
84
+ - **`ask-marcel login --use-extension` is removed.** The companion browser
85
+ extension and the system-browser / localhost-callback capture path are gone
86
+ (`browser-extension/`, the `system-browser-auth` + `token-callback-server`
87
+ infra, and the `--use-extension` flag). `ask-marcel-office login` — a
88
+ Playwright-driven Edge/Chrome window that captures all four tokens in one
89
+ session — is the only login flow. The token cache format is unchanged;
90
+ existing sessions keep working without re-login.
91
+
92
+ ### Added
93
+
94
+ - **`get-schedule`** — free/busy availability for a comma-separated list of
95
+ people and/or meeting rooms over a time window
96
+ (`POST /me/calendar/getSchedule`, `Calendars.Read` — already on the basic
97
+ token). Returns each person's `availabilityView` slot string (0 free /
98
+ 1 tentative / 2 busy / 3 OOF / 4 working-elsewhere), the underlying busy
99
+ blocks, and their working hours. Both bounds accept the relative-date
100
+ vocabulary (`today`, `+1d`, `start-of-week`, …).
101
+ - **`create-reply-draft`** — create a threaded reply-all draft to an existing
102
+ message (`createReplyAll` + a body patch), so an agent can prepare a response
103
+ in-thread. Produces an UNSENT draft only — like `create-mail-draft` /
104
+ `update-mail-draft`, the CLI can never send. (Third and last write command.)
105
+ - **Teams substrate tokens now self-heal on the command path.** When a
106
+ chatsvcagg or ic3 token lapses (~hourly), the CLI redeems the shared Teams
107
+ refresh token for that substrate audience over HTTP — headless, no browser —
108
+ instead of dead-ending in a "run `ask-marcel-office login`" error. The four
109
+ Teams chat commands (`list-teams-chats-with-messages`, `list-teams-chat-messages`,
110
+ `get-teams-chat-message`, `find-chats-with-user`) plus `list-teams-chat-history`
111
+ now keep working for as long as your Graph token does, rather than dying an hour
112
+ into a session. Falls back to the interactive-login prompt only when no refresh
113
+ token is cached or Entra ID rejects the redemption. The elevated token
114
+ (historical-version downloads) is unaffected — a different app identity with no
115
+ shared-RT path — and still needs `login` when it lapses.
116
+
117
+ ### Changed
118
+
119
+ - The npm tarball no longer double-ships the ~500 KB command manifest:
120
+ `docs/commands.json` was dropped from `files[]` (the importable
121
+ `ask-marcel-office-cli/commands.json` subpath still resolves to
122
+ `dist/commands.json`, which remains). Unpacked size ~3.5 → ~3.0 MB.
123
+
124
+ ### Internal
125
+
126
+ - Privacy scrub: personal/tenant fixture data and internal audit-session
127
+ labels removed across source, tests, fixtures, and docs — and purged from
128
+ the entire git history (rewritten and force-pushed).
129
+ - Dead code removed: the single-token browser capture (`acquireToken`), two
130
+ orphan probe scripts, an unused env module; the four graph-client
131
+ auth-header closures collapsed into one factory.
132
+
5
133
  ## 1.5.2
6
134
 
7
135
  ### Fixed
@@ -29,9 +157,11 @@ All notable changes to `ask-marcel-office-cli` are documented here.
29
157
  each launched a _visible_ browser that "opens and closes within seconds" to
30
158
  silently re-capture — per command, per process, with no cross-process throttle —
31
159
  so after the short-lived elevated token (~59 min) expired, every elevated or
32
- Teams-chat command popped a window. The command-path auth now **fails fast** with
33
- an actionable "run `ask-marcel login`" instead; browser capture is reserved for
34
- the explicit `login` command, which re-captures all four tokens in one session.
160
+ Teams-chat command popped a window. The command-path auth now **self-heals** the
161
+ chat-substrate tokens with a headless refresh of the shared Teams RT (and, when
162
+ that can't renew them, fails fast with an actionable "run `ask-marcel-office
163
+ login`") instead; interactive browser capture is reserved for the explicit
164
+ `login` command, which re-captures all four tokens in one session.
35
165
 
36
166
  ## 1.5.0
37
167
 
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # ask-marcel-office-cli
2
2
 
3
- **A Microsoft Graph CLI built for LLMs.** 177 commands across Mail, Calendar, OneDrive, SharePoint, Excel, Teams chats, Planner / To-Do, OneNote, and directory — plus local-file tools (markdown conversion, image extraction) that need no sign-in at all. Sign in once with your Microsoft 365 account — no Azure app registration, no admin consent, no client secrets.
3
+ **A Microsoft Graph CLI built for LLMs.** 180 commands across Mail, Calendar, OneDrive, SharePoint, Excel, Teams chats, Planner / To-Do, OneNote, and directory — plus local-file tools (markdown conversion, image extraction) that need no sign-in at all. Sign in once with your Microsoft 365 account — no Azure app registration, no admin consent, no client secrets.
4
4
 
5
5
  ```bash
6
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
7
+ ask-marcel-office login # browser opens once, token cached
8
+ ask-marcel-office my-quick-context # who am I + my IDs, in one round trip
9
+ ask-marcel-office list-mail-messages --top 5
10
10
  ```
11
11
 
12
12
  ---
@@ -19,13 +19,13 @@ LLM tool-loops keep hitting the same three walls with Microsoft Graph:
19
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
20
  3. **Errors are opaque.** `BadRequest: Invalid filter clause` doesn't tell a model what to fix.
21
21
 
22
- `ask-marcel` fixes all three at the CLI layer, so the model just calls commands and reads back-pressure-friendly responses.
22
+ `ask-marcel-office` fixes all three at the CLI layer, so the model just calls commands and reads back-pressure-friendly responses.
23
23
 
24
24
  ## What you get
25
25
 
26
26
  ### Read-only by design
27
27
 
28
- **This is the most important property.** 173 GET endpoints + 2 POST (searches) + 1 POST (create draft) + 1 PATCH (update draft) = 177 commands. No `send-mail`, no `create-event`, no `upload-file`, no `delete-anything`. The only write operations are draft creation and update — a hallucinated command can at most create an unsent draft in your Drafts folder. Safe default for autonomous agents, MCP servers, and "let Claude poke around my mailbox" sessions where you can't fully review every tool call.
28
+ **This is the most important property.** 173 GET endpoints + 3 read-only POST (two searches + free/busy lookup) + 3 POST (create mail draft / threaded reply draft / forward draft) + 1 PATCH (update draft) = 180 commands. No `send-mail`, no `create-event`, no `upload-file`, no `delete-anything`. The only write operations are draft creation (a new mail, a threaded reply-all, or a forward) and update — a hallucinated command can at most create an unsent draft in your Drafts folder. 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
29
 
30
30
  ### One call gets the full email context
31
31
 
@@ -56,7 +56,7 @@ Pass `--include-metadata true` on any `*-as-markdown` (or `convert-mail-attachme
56
56
 
57
57
  ### Extract embedded images from documents
58
58
 
59
- `extract-drive-item-images` (OneDrive / SharePoint), `extract-mail-attachment-images` (Outlook attachments), and `extract-local-file-images` (a file **on disk** — no Graph, no login) pull the embedded images out of a **docx, xlsx, pptx, or pdf**. For Office files it reads the OOXML media parts (png/jpg/gif/bmp/tiff/webp/svg) — including original full-resolution / un-cropped originals and images on hidden slides that the rendered view never shows. SVG rides back as its XML source (which carries the diagram's own text labels); legacy vector (emf/wmf) and audio/video are skipped. For a PDF it walks every page via [unpdf](https://github.com/unjs/unpdf) (a pure-JS, no-native-deps pdf.js build) and re-encodes each painted image as PNG — page-oriented, so it captures images as drawn on each page (it does not reach layer-hidden/unpainted XObjects or the full uncropped original behind a clipped image). Pair with the global `--output-dir <dir>` to write every image to a folder (the directory is auto-created and each `base64` becomes a `savedTo` path); without it the bytes ride back base64-encoded so a vision model can read them directly.
59
+ `extract-drive-item-images` (OneDrive / SharePoint), `extract-mail-attachment-images` (Outlook attachments), and `extract-local-file-images` (a file **on disk** — no Graph, no login) pull the embedded images out of a **docx, xlsx, pptx, or pdf**. For Office files it reads the OOXML media parts (png/jpg/gif/bmp/tiff/webp/svg) — including original full-resolution / un-cropped originals and images on hidden slides that the rendered view never shows. SVG rides back as its XML source (which carries the diagram's own text labels); legacy vector (emf/wmf) and audio/video are skipped. For a PDF it walks every page via [unpdf](https://github.com/unjs/unpdf) (a pure-JS, no-native-deps pdf.js build) and re-encodes each painted image as PNG — page-oriented, so it captures images as drawn on each page (it does not reach layer-hidden/unpainted XObjects or the full uncropped original behind a clipped image). Pair with the global `--output-dir <dir>` to write every image to a folder (the directory is auto-created and each `base64` becomes a `savedTo` path); without it the bytes ride back base64-encoded so a vision model can read them directly. The same OOXML / PDF image extraction runs over every file **inside a `.zip`** when you pass `convert-local-file --include-images true`: each archive entry gains an `images` array, so a screenshot pasted into a zipped document is still reachable in one call.
60
60
 
61
61
  The CLI follows any SharePoint media-transform redirect internally, so the LLM never has to fetch an external URL.
62
62
 
@@ -68,21 +68,13 @@ The CLI follows any SharePoint media-transform redirect internally, so the LLM n
68
68
 
69
69
  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.
70
70
 
71
- **Login flow:** By default, the CLI uses Playwright to open a browser for authentication. Alternatively, you can use the [Ask Marcel Companion](./browser-extension/) browser extension for faster authentication.
71
+ **Login flow:** the CLI drives a Playwright-launched Edge/Chrome window through the Teams sign-in, captures the tokens, and caches them at `~/.ask-marcel/token-cache.json` (0600). Running `login` again (even when already signed in) reports all four cached tokens — basic, elevated (M365), and the two Teams-chat substrate tokens (chatsvcagg / ic3) — each with its time-left and refresh route: basic/chatsvcagg/ic3 refresh automatically from the cached refresh token, while the elevated token is re-captured only on an interactive login. `login --force` ignores the cache and re-captures every token in one browser pass (the persistent profile is reused, so you are usually not re-prompted for credentials) — the only way to refresh the elevated token while the basic one is still valid. `scopes-check` reports the same four tokens without opening a browser.
72
72
 
73
73
  ```bash
74
- ask-marcel login # default: Playwright browser
75
- ask-marcel login --use-extension # use browser extension (requires setup)
74
+ ask-marcel-office login # sign in, or show all four tokens' status if already signed in
75
+ ask-marcel-office login --force # re-capture every token, ignoring the cache
76
76
  ```
77
77
 
78
- **Browser extension setup (optional, one-time):**
79
-
80
- 1. Open `chrome://extensions/` (Chrome) or `edge://extensions/` (Edge)
81
- 2. Enable "Developer mode" (top-right toggle)
82
- 3. Click "Load unpacked" → select the `browser-extension/` folder from this repo
83
- 4. **Enable in incognito/inprivate mode:** Click the extension's "Details" button, then enable "Allow in incognito" (Chrome) or "Allow in InPrivate" (Edge). **This is required** — the CLI opens an incognito/inprivate window, and extensions are disabled there by default.
84
- 5. Done — use `ask-marcel login --use-extension` to authenticate via the extension
85
-
86
78
  ### Stable error envelope with actionable hints
87
79
 
88
80
  Every failure — Graph, CLI parser, Zod validation, substrate — comes back as `{ok: false, error, errorCode?, hint?, source, retryAfterSeconds?}`. 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`"). When Graph throttles (HTTP 429, sometimes 503) the response's `Retry-After` is surfaced as `retryAfterSeconds` — the integer seconds to wait — so a caller running tenant-scale crawls can honor the server's backoff instead of guessing.
@@ -111,14 +103,14 @@ Two flag patterns avoid the round-trip:
111
103
  npm i -g ask-marcel-office-cli
112
104
 
113
105
  # authenticate (cached → refresh → browser fallback)
114
- ask-marcel login
106
+ ask-marcel-office login
115
107
 
116
108
  # the rest is read-only (the only writes are mail drafts) and discoverable from --help
117
- ask-marcel list-drives
118
- ask-marcel search-onedrive-files --drive-id "b!abc..." --query "Q3 budget"
119
- ask-marcel convert-mail-to-markdown --message-id "AAMkAD..."
120
- ask-marcel list-calendar-view --start-date-time today --end-date-time +7d
121
- ask-marcel convert-mail-attachment-to-pdf \
109
+ ask-marcel-office list-drives
110
+ ask-marcel-office search-onedrive-files --drive-id "b!abc..." --query "Q3 budget"
111
+ ask-marcel-office convert-mail-to-markdown --message-id "AAMkAD..."
112
+ ask-marcel-office list-calendar-view --start-date-time today --end-date-time +7d
113
+ ask-marcel-office convert-mail-attachment-to-pdf \
122
114
  --message-id "AAMkAD..." --attachment-id "AAMkAD...attach1" \
123
115
  --output-path /tmp/deck.pdf
124
116
  ```
@@ -129,11 +121,11 @@ Five discovery surfaces, each tuned for a different audience and token budget:
129
121
 
130
122
  | When you want | Run | Returns |
131
123
  |---|---|---|
132
- | Help with a single command | `ask-marcel <command> --help` | Required flags, optional flags, an example, pagination notes |
133
- | A scan of every command | `ask-marcel --help` | One-sentence summary per command, grouped by category |
134
- | 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 |
135
- | 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 |
136
- | Rich docs for one command | `ask-marcel docs <command>` | Full Markdown to stdout (response shape, examples, the underlying Graph endpoint, Microsoft Learn link) |
124
+ | Help with a single command | `ask-marcel-office <command> --help` | Required flags, optional flags, an example, pagination notes |
125
+ | A scan of every command | `ask-marcel-office --help` | One-sentence summary per command, grouped by category |
126
+ | The slim LLM-friendly index | `ask-marcel-office 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 |
127
+ | The slim index for one domain | `ask-marcel-office 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 |
128
+ | Rich docs for one command | `ask-marcel-office docs <command>` | Full Markdown to stdout (response shape, examples, the underlying Graph endpoint, Microsoft Learn link) |
137
129
 
138
130
  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.
139
131
 
@@ -141,7 +133,7 @@ Pair `help-json --terse --category <name>` with `docs <command>` for the canonic
141
133
 
142
134
  Most agents already know how to read JSON from stdout. Two patterns work:
143
135
 
144
- **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.
136
+ **1. Drop in as a shell tool** — the agent learns the manifest, then runs `ask-marcel-office <command> --output json`. The slim defaults + structured error hints mean it can self-recover from typos.
145
137
 
146
138
  **2. Embed as a library** — every command is exported. Compose it inside your own MCP server, Claude Agent, or LangChain tool:
147
139
 
@@ -185,39 +177,11 @@ The `AuthManager` interface is two async methods that return `Result<T, AuthErro
185
177
 
186
178
  ## Deep docs
187
179
 
188
- - **[All 177 commands](docs/COMMANDS.md)** — per-category tables with required params + Graph endpoint
180
+ - **[All 180 commands](docs/COMMANDS.md)** — per-category tables with required params + Graph endpoint
189
181
  - **[Usage guide](docs/USAGE.md)** — output formats, OData passthrough, `--output-path`, pagination, library API, architecture, configuration, quality gates
190
182
  - **[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'`
191
183
  - **[QA playbook](docs/QA-PLAYBOOK.md)** — the repeatable full-surface health-check procedure (offline gates, parameter matrix, conversion contracts, live Graph drift probes) used to audit each release
192
184
 
193
-
194
- ## Agent skill (progressive disclosure)
195
-
196
- A [Codex skill](https://docs.anthropic.com/en/docs/agents-and-tools/codex) lives at `.agents/skills/ask-marcel-office/` and teaches agents how to use the CLI without loading all 177 commands into context at once.
197
-
198
- **Structure**
199
-
200
- ```
201
- .agents/skills/ask-marcel-office/
202
- ├── SKILL.md # core workflow + category index
203
- └── references/ # per-domain command details, loaded on demand
204
- ├── marcel-mail.md (32 commands)
205
- ├── marcel-drive.md (30 commands)
206
- ├── marcel-calendar.md (23 commands)
207
- ├── marcel-sharepoint.md (18 commands)
208
- ├── marcel-user.md (15 commands)
209
- ├── marcel-tasks.md (15 commands)
210
- ├── marcel-excel.md (11 commands)
211
- ├── marcel-notes.md (11 commands)
212
- ├── marcel-chats.md (9 commands)
213
- ├── marcel-teams.md (7 commands)
214
- └── marcel-meta.md (6 commands)
215
- ```
216
-
217
- **How it works**
218
-
219
- `SKILL.md` contains the authentication flow, the discovery loop (`help-json --terse --category` → `docs <cmd>` → execute), key patterns (OData passthrough, relative dates, document conversion, pagination), and a category index. The full command reference for each domain lives in `references/marcel-<category>.md` and is loaded only when the agent needs that domain — keeping the context window lean.
220
-
221
185
  ## Roadmap
222
186
 
223
187
  Read-only stays the default forever. There's no fixed feature backlog — coverage grows out of real LLM workflows as they come up.