ask-marcel-office-cli 1.5.2 → 2.0.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 (32) hide show
  1. package/CHANGELOG.md +67 -3
  2. package/README.md +21 -58
  3. package/dist/cli.js +1532 -1722
  4. package/dist/commands.json +382 -273
  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 +1410 -1604
  9. package/dist/infra/auth.d.ts +6 -20
  10. package/dist/infra/browser-auth.d.ts +11 -12
  11. package/dist/infra/graph-client.d.ts +2 -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/create-reply-draft.d.ts +14 -0
  16. package/dist/use-cases/commands/docs.d.ts +1 -1
  17. package/dist/use-cases/commands/get-schedule.d.ts +11 -0
  18. package/dist/use-cases/commands/graph-scopes.d.ts +1 -1
  19. package/dist/use-cases/commands/iso-datetime-schema.d.ts +1 -1
  20. package/dist/use-cases/commands/markdown-pipeline.d.ts +5 -5
  21. package/dist/use-cases/commands/option-descriptions.d.ts +1 -1
  22. package/dist/use-cases/commands/output-path.d.ts +4 -4
  23. package/dist/use-cases/commands/zip-archive-to-markdown.d.ts +1 -1
  24. package/dist/use-cases/ports/filesystem.d.ts +1 -1
  25. package/docs/COMMANDS.md +14 -12
  26. package/docs/USAGE.md +23 -23
  27. package/package.json +3 -4
  28. package/dist/composition/env.d.ts +0 -2
  29. package/dist/infra/system-browser-auth.d.ts +0 -35
  30. package/dist/infra/system-browser-loader.d.ts +0 -3
  31. package/dist/infra/token-callback-server.d.ts +0 -31
  32. package/docs/commands.json +0 -7676
package/docs/USAGE.md CHANGED
@@ -15,15 +15,15 @@ npm i -g ask-marcel-office-cli
15
15
  bun add -g ask-marcel-office-cli
16
16
 
17
17
  # authenticate (cached → refresh → browser fallback)
18
- ask-marcel login
18
+ ask-marcel-office login
19
19
 
20
20
  # the rest is discoverable
21
- ask-marcel --help # ~34 KB, one-sentence summaries
22
- ask-marcel help-json --terse --category mail # ~6 KB JSON for one category
23
- ask-marcel docs list-mail-messages # full per-command Markdown
21
+ ask-marcel-office --help # ~34 KB, one-sentence summaries
22
+ ask-marcel-office help-json --terse --category mail # ~6 KB JSON for one category
23
+ ask-marcel-office docs list-mail-messages # full per-command Markdown
24
24
  ```
25
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.
26
+ `ask-marcel-office 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
27
 
28
28
  The first launch prints a one-time notice if a newer version is on npm.
29
29
 
@@ -36,12 +36,12 @@ Every command writes its output as a single document to **stdout** (success or e
36
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:`, `source:`, and (when Graph throttles) `retryAfter: Ns` 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
37
 
38
38
  ```bash
39
- $ ask-marcel get-current-user
39
+ $ ask-marcel-office get-current-user
40
40
  id: 0c1d2e3f-…
41
- displayName: Vincent Delacourt
42
- mail: vincent@example.com
41
+ displayName: Jordan Avery
42
+ mail: jordan.avery@example.com
43
43
 
44
- $ ask-marcel list-mail-folder-messages --mail-folder-id inbox --top 2
44
+ $ ask-marcel-office list-mail-folder-messages --mail-folder-id inbox --top 2
45
45
  id: AAMkAGI2…
46
46
  subject: Re: Q2 planning
47
47
  from: alice@example.com
@@ -52,7 +52,7 @@ from: bob@example.com
52
52
 
53
53
  --- next: https://graph.microsoft.com/v1.0/me/messages?$skip=2
54
54
 
55
- $ ask-marcel get-mail-message --message-id "bad-id"
55
+ $ ask-marcel-office get-mail-message --message-id "bad-id"
56
56
  error: ErrorInvalidIdMalformed: Id is malformed.
57
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
58
  source: graph
@@ -102,9 +102,9 @@ The stable `{ok, data, nextLink?, deltaLink?, count?}` envelope, unambiguous for
102
102
  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:
103
103
 
104
104
  ```bash
105
- ask-marcel list-mail-messages --top 5 --select id,subject,from,receivedDateTime
106
- ask-marcel list-recent-files --filter "name eq 'budget.xlsx'" --orderby lastModifiedDateTime desc
107
- ask-marcel list-folder-files --drive-id b!abc --item-id 01DEF --select id,name --top 10
105
+ ask-marcel-office list-mail-messages --top 5 --select id,subject,from,receivedDateTime
106
+ ask-marcel-office list-recent-files --filter "name eq 'budget.xlsx'" --orderby lastModifiedDateTime desc
107
+ ask-marcel-office list-folder-files --drive-id b!abc --item-id 01DEF --select id,name --top 10
108
108
  ```
109
109
 
110
110
  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.**
@@ -124,10 +124,10 @@ Narrower variants (a sample — see each command's `--help` for the exact list):
124
124
  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":
125
125
 
126
126
  ```bash
127
- ask-marcel list-calendar-view --start-date-time "start-of-week" --end-date-time "end-of-week"
128
- ask-marcel list-calendar-view --start-date-time "today" --end-date-time "+7d"
129
- ask-marcel list-calendar-view --start-date-time "monday" --end-date-time "next-monday"
130
- ask-marcel list-calendar-view --start-date-time "start-of-month" --end-date-time "end-of-month"
127
+ ask-marcel-office list-calendar-view --start-date-time "start-of-week" --end-date-time "end-of-week"
128
+ ask-marcel-office list-calendar-view --start-date-time "today" --end-date-time "+7d"
129
+ ask-marcel-office list-calendar-view --start-date-time "monday" --end-date-time "next-monday"
130
+ ask-marcel-office list-calendar-view --start-date-time "start-of-month" --end-date-time "end-of-month"
131
131
  ```
132
132
 
133
133
  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.
@@ -137,7 +137,7 @@ Accepted shapes (UTC, week starts Monday): strict ISO; date-only (`2026-04-01`
137
137
  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:
138
138
 
139
139
  ```bash
140
- ask-marcel convert-mail-attachment-to-pdf \
140
+ ask-marcel-office convert-mail-attachment-to-pdf \
141
141
  --message-id "AAMkAD..." --attachment-id "AAMkAD...attach1" \
142
142
  --output-path /tmp/deck.pdf
143
143
  # Text mode:
@@ -158,21 +158,21 @@ When a response contains a `nextLink` cursor, feed that URL back through `next-p
158
158
 
159
159
  ```bash
160
160
  # page 1
161
- ask-marcel --output json list-mail-folders > p1.json
161
+ ask-marcel-office --output json list-mail-folders > p1.json
162
162
 
163
163
  # page 2..N — loop until nextLink is gone
164
164
  next=$(jq -r '.nextLink // empty' p1.json)
165
165
  while [ -n "$next" ]; do
166
- ask-marcel --output json next-page --url "$next" > pN.json
166
+ ask-marcel-office --output json next-page --url "$next" > pN.json
167
167
  next=$(jq -r '.nextLink // empty' pN.json)
168
168
  done
169
169
  ```
170
170
 
171
- 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.
171
+ Every paginated command advertises this in three places: `ask-marcel-office <cmd> --help` prints a `Pagination:` line, `ask-marcel-office docs <cmd>` adds a `**Pagination:**` field, and [`docs/commands.json`](commands.json) ships `"pagination": true` on each entry so agents can detect it programmatically.
172
172
 
173
173
  ## Quick context
174
174
 
175
- `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.
175
+ `ask-marcel-office 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.
176
176
 
177
177
  ## Library API
178
178
 
@@ -231,7 +231,7 @@ src/
231
231
 
232
232
  `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.
233
233
 
234
- 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.
234
+ 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, 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.
235
235
 
236
236
  ## Configuration
237
237
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ask-marcel-office-cli",
3
- "version": "1.5.2",
3
+ "version": "2.0.0",
4
4
  "description": "Microsoft Graph CLI + library \u2014 typed Bun/TypeScript wrapper around 150+ Graph operations (read + on-the-fly PDF/markdown conversion + federated Microsoft Search) reachable from a Teams browser-OAuth token.",
5
5
  "license": "MIT",
6
6
  "author": "Vincent Delacourt <vincent.delacourt@adama-development.com>",
@@ -25,11 +25,10 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "bin": {
28
- "ask-marcel": "./dist/cli.js"
28
+ "ask-marcel-office": "./dist/cli.js"
29
29
  },
30
30
  "files": [
31
31
  "dist/",
32
- "docs/commands.json",
33
32
  "docs/COMMANDS.md",
34
33
  "docs/USAGE.md",
35
34
  "CHANGELOG.md",
@@ -69,7 +68,7 @@
69
68
  "docs:gen": "bun run scripts/gen-docs.ts",
70
69
  "build": "rm -rf dist && bun run docs:gen && bun run build:js && bun run build:types && bun run scripts/fix-dts-extensions.ts && bun run scripts/add-shebang.ts && cp docs/commands.json dist/commands.json",
71
70
  "prepublishOnly": "bun run build && bun test && bun run lint:strict && bun run typecheck && bun run coverage",
72
- "build:bin": "mkdir -p dist/bin && bun build src/main.ts --compile --target=bun-darwin-arm64 --external playwright --outfile dist/bin/ask-marcel-mac-arm64 && bun build src/main.ts --compile --target=bun-darwin-x64 --external playwright --outfile dist/bin/ask-marcel-mac-x64 && bun build src/main.ts --compile --target=bun-linux-x64 --external playwright --outfile dist/bin/ask-marcel-linux && bun build src/main.ts --compile --target=bun-windows-x64 --external playwright --outfile dist/bin/ask-marcel-windows.exe"
71
+ "build:bin": "mkdir -p dist/bin && bun build src/main.ts --compile --target=bun-darwin-arm64 --external playwright --outfile dist/bin/ask-marcel-office-mac-arm64 && bun build src/main.ts --compile --target=bun-darwin-x64 --external playwright --outfile dist/bin/ask-marcel-office-mac-x64 && bun build src/main.ts --compile --target=bun-linux-x64 --external playwright --outfile dist/bin/ask-marcel-office-linux && bun build src/main.ts --compile --target=bun-windows-x64 --external playwright --outfile dist/bin/ask-marcel-office-windows.exe"
73
72
  },
74
73
  "devDependencies": {
75
74
  "@eslint/js": "^9.28.0",
@@ -1,2 +0,0 @@
1
- import type { EnvVar } from '../domain/env-var.js';
2
- export declare const getEnvOrThrow: (key: string) => EnvVar;
@@ -1,35 +0,0 @@
1
- import type { AccessToken } from '../domain/access-token.js';
2
- import type { Result } from '../domain/result.js';
3
- import type { Logger } from '../use-cases/ports/logger.js';
4
- type SystemBrowserAuthDeps = {
5
- readonly logger: Logger;
6
- readonly timeoutMs?: number;
7
- readonly extensionTimeoutMs?: number;
8
- };
9
- type SystemBrowserTokenResult = {
10
- readonly accessToken: AccessToken;
11
- readonly refreshToken: string | null;
12
- readonly elevatedAccessToken?: AccessToken | null;
13
- readonly chatsvcaggAccessToken?: AccessToken | null;
14
- readonly ic3AccessToken?: AccessToken | null;
15
- readonly chatsvcaggRegion?: string;
16
- };
17
- type SystemBrowserAuthError = {
18
- type: 'server_bind_failed';
19
- message: string;
20
- } | {
21
- type: 'browser_open_failed';
22
- message: string;
23
- } | {
24
- type: 'extension_timeout';
25
- message: string;
26
- } | {
27
- type: 'invalid_token';
28
- message: string;
29
- } | {
30
- type: 'cancelled';
31
- message: string;
32
- };
33
- declare const authenticateViaSystemBrowser: (deps: SystemBrowserAuthDeps) => Promise<Result<SystemBrowserTokenResult, SystemBrowserAuthError>>;
34
- export { authenticateViaSystemBrowser };
35
- export type { SystemBrowserAuthDeps, SystemBrowserAuthError, SystemBrowserTokenResult };
@@ -1,3 +0,0 @@
1
- import type { Logger } from '../use-cases/ports/logger.js';
2
- import type { SystemBrowserAuthFn } from './auth.js';
3
- export declare const defaultSystemBrowserAuth: (logger: Logger, skipSystemBrowser: boolean) => SystemBrowserAuthFn;
@@ -1,31 +0,0 @@
1
- import type { Result } from '../domain/result.js';
2
- import type { Logger } from '../use-cases/ports/logger.js';
3
- type TokenCallbackPayload = {
4
- readonly access_token: string;
5
- readonly refresh_token?: string;
6
- readonly elevated_access_token?: string;
7
- readonly chatsvcagg_access_token?: string;
8
- readonly ic3_access_token?: string;
9
- readonly chatsvcagg_region?: string;
10
- };
11
- type TokenCallbackServer = {
12
- readonly port: number;
13
- readonly start: () => Promise<Result<TokenCallbackPayload, TokenCallbackError>>;
14
- readonly stop: () => Promise<void>;
15
- };
16
- type TokenCallbackError = {
17
- type: 'bind_failed';
18
- message: string;
19
- } | {
20
- type: 'timeout';
21
- message: string;
22
- } | {
23
- type: 'invalid_payload';
24
- message: string;
25
- } | {
26
- type: 'server_closed';
27
- message: string;
28
- };
29
- declare const createTokenCallbackServer: (logger: Logger, timeoutMs?: number) => TokenCallbackServer;
30
- export { createTokenCallbackServer };
31
- export type { TokenCallbackError, TokenCallbackPayload, TokenCallbackServer };