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.
- package/CHANGELOG.md +133 -3
- package/README.md +23 -59
- package/dist/cli.js +1757 -1766
- package/dist/commands.json +437 -275
- package/dist/composition/build-deps.d.ts +7 -8
- package/dist/composition/cli.d.ts +5 -4
- package/dist/domain/iso-datetime.d.ts +1 -1
- package/dist/index.js +1606 -1653
- package/dist/infra/auth.d.ts +37 -21
- package/dist/infra/browser-auth.d.ts +13 -12
- package/dist/infra/graph-client.d.ts +28 -2
- package/dist/presenter/error-hints.d.ts +9 -9
- package/dist/use-cases/commands/build-command.d.ts +1 -1
- package/dist/use-cases/commands/command-types.d.ts +5 -5
- package/dist/use-cases/commands/convert-local-file.d.ts +4 -0
- package/dist/use-cases/commands/create-forward-draft.d.ts +12 -0
- package/dist/use-cases/commands/create-reply-draft.d.ts +10 -0
- package/dist/use-cases/commands/docs.d.ts +1 -1
- package/dist/use-cases/commands/get-schedule.d.ts +11 -0
- package/dist/use-cases/commands/graph-scopes.d.ts +1 -1
- package/dist/use-cases/commands/image-extraction.d.ts +2 -1
- package/dist/use-cases/commands/iso-datetime-schema.d.ts +1 -1
- package/dist/use-cases/commands/login-status.d.ts +31 -0
- package/dist/use-cases/commands/login.d.ts +3 -1
- package/dist/use-cases/commands/markdown-pipeline.d.ts +5 -5
- package/dist/use-cases/commands/option-descriptions.d.ts +1 -1
- package/dist/use-cases/commands/output-path.d.ts +4 -4
- package/dist/use-cases/commands/parse-recipients.d.ts +14 -0
- package/dist/use-cases/commands/zip-archive-to-markdown.d.ts +4 -2
- package/dist/use-cases/ports/filesystem.d.ts +1 -1
- package/docs/COMMANDS.md +16 -13
- package/docs/USAGE.md +23 -23
- package/package.json +3 -4
- package/dist/composition/env.d.ts +0 -2
- package/dist/infra/system-browser-auth.d.ts +0 -35
- package/dist/infra/system-browser-loader.d.ts +0 -3
- package/dist/infra/token-callback-server.d.ts +0 -31
- package/docs/commands.json +0 -7676
package/dist/infra/auth.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { BrowserAuth, ElevatedFailureReason } from './browser-auth.js';
|
|
|
6
6
|
type AuthError = {
|
|
7
7
|
type: 'auth_failed';
|
|
8
8
|
message: string;
|
|
9
|
+
code?: string;
|
|
9
10
|
} | {
|
|
10
11
|
type: 'auth_cancelled';
|
|
11
12
|
};
|
|
@@ -15,7 +16,7 @@ type AuthError = {
|
|
|
15
16
|
* `{ elevated: 'captured' | 'failed', elevatedReason?: ... }` field on
|
|
16
17
|
* the login response so an LLM consumer can predict whether the
|
|
17
18
|
* elevated-dependent commands (chat metadata, historical-version
|
|
18
|
-
* downloads) will work without invoking them.
|
|
19
|
+
* downloads) will work without invoking them.
|
|
19
20
|
*/
|
|
20
21
|
type ElevatedOutcome = {
|
|
21
22
|
captured: true;
|
|
@@ -24,7 +25,9 @@ type ElevatedOutcome = {
|
|
|
24
25
|
reason: ElevatedFailureReason | 'unknown_error';
|
|
25
26
|
};
|
|
26
27
|
type AuthManager = {
|
|
27
|
-
getAccessToken: (
|
|
28
|
+
getAccessToken: (options?: {
|
|
29
|
+
force?: boolean;
|
|
30
|
+
}) => Promise<Result<AccessToken, AuthError>>;
|
|
28
31
|
/**
|
|
29
32
|
* Returns a Graph token issued for an app on Microsoft's ODSP
|
|
30
33
|
* `logicalPermissions` allow-list. Falls through cache → re-capture
|
|
@@ -60,7 +63,6 @@ type AuthManager = {
|
|
|
60
63
|
* Inspect the elevated-capture outcome from the most recent
|
|
61
64
|
* `acquireViaBrowser` invocation. Returns null if no browser-acquired
|
|
62
65
|
* session has happened in this process (cache hit / refresh-only).
|
|
63
|
-
* Login-fix round-1 Wave D.
|
|
64
66
|
*/
|
|
65
67
|
getLastElevatedOutcome: () => ElevatedOutcome | null;
|
|
66
68
|
/**
|
|
@@ -69,22 +71,39 @@ type AuthManager = {
|
|
|
69
71
|
* as `getLastElevatedOutcome`.
|
|
70
72
|
*/
|
|
71
73
|
getLastChatsvcaggOutcome: () => ElevatedOutcome | null;
|
|
74
|
+
/**
|
|
75
|
+
* Decode-only preflight for whether the *persisted* elevated
|
|
76
|
+
* (M365ChatClient) token is present and still usable — the token the
|
|
77
|
+
* historical-version download / convert commands need. Unlike
|
|
78
|
+
* `getLastElevatedOutcome` (per-process, null in a fresh CLI invocation),
|
|
79
|
+
* this reads the on-disk cache, so a separate `deep-scan` run can tell
|
|
80
|
+
* "elevated available" from "run `login` first" without provoking a 403.
|
|
81
|
+
* Optional: only the real manager implements it; a minimal fake omits it
|
|
82
|
+
* and callers treat that as unavailable. Never captures or refreshes.
|
|
83
|
+
*/
|
|
84
|
+
getCachedElevatedInfo?: () => Promise<{
|
|
85
|
+
available: boolean;
|
|
86
|
+
expiresInSeconds: number | undefined;
|
|
87
|
+
}>;
|
|
88
|
+
/**
|
|
89
|
+
* Same decode-only preflight as `getCachedElevatedInfo`, for the chatsvcagg /
|
|
90
|
+
* ic3 Teams-chat substrate tokens. `login`'s four-token status and
|
|
91
|
+
* `scopes-check` read these; a minimal fake omits them and callers treat that
|
|
92
|
+
* as unavailable.
|
|
93
|
+
*/
|
|
94
|
+
getCachedChatsvcaggInfo?: () => Promise<{
|
|
95
|
+
available: boolean;
|
|
96
|
+
expiresInSeconds: number | undefined;
|
|
97
|
+
}>;
|
|
98
|
+
getCachedIc3Info?: () => Promise<{
|
|
99
|
+
available: boolean;
|
|
100
|
+
expiresInSeconds: number | undefined;
|
|
101
|
+
}>;
|
|
72
102
|
};
|
|
73
|
-
|
|
74
|
-
accessToken: AccessToken;
|
|
75
|
-
refreshToken: string | null;
|
|
76
|
-
elevatedAccessToken?: AccessToken | null;
|
|
77
|
-
chatsvcaggAccessToken?: AccessToken | null;
|
|
78
|
-
ic3AccessToken?: AccessToken | null;
|
|
79
|
-
chatsvcaggRegion?: string;
|
|
80
|
-
}, {
|
|
81
|
-
type: string;
|
|
82
|
-
message: string;
|
|
83
|
-
}>>;
|
|
84
|
-
declare const createAuthManagerFromApi: (browserAuth: BrowserAuth, cachePath: string, browserProfileDir: string, logger: Logger, fs: FileSystem, systemBrowserAuthFn?: SystemBrowserAuthFn, usePlaywrightFallback?: boolean, skipSystemBrowser?: boolean, recaptureSecondaryViaBrowser?: boolean) => AuthManager;
|
|
103
|
+
declare const createAuthManagerFromApi: (browserAuth: BrowserAuth, cachePath: string, browserProfileDir: string, logger: Logger, fs: FileSystem, recaptureSecondaryViaBrowser?: boolean) => AuthManager;
|
|
85
104
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
105
|
+
* Probe the token cache for a fresh access token. Handed to the browser
|
|
106
|
+
* capture so its poll loop can short-circuit the multi-minute dance
|
|
88
107
|
* when a concurrent process refreshes first (AAD rotates SPA refresh tokens,
|
|
89
108
|
* so the loser of the race cannot refresh and falls into the browser leg).
|
|
90
109
|
* Exported for the composition test; pure read, never writes.
|
|
@@ -96,10 +115,7 @@ declare const createAuthManager: (deps: {
|
|
|
96
115
|
logger: Logger;
|
|
97
116
|
fs?: FileSystem;
|
|
98
117
|
browserProfileDir?: string;
|
|
99
|
-
systemBrowserAuth?: SystemBrowserAuthFn;
|
|
100
|
-
usePlaywrightFallback?: boolean;
|
|
101
|
-
skipSystemBrowser?: boolean;
|
|
102
118
|
recaptureSecondaryViaBrowser?: boolean;
|
|
103
119
|
}) => AuthManager;
|
|
104
120
|
export { createAuthManager, createAuthManagerFromApi, createFreshCachedTokenProbe, stderrProgress };
|
|
105
|
-
export type { AuthError, AuthManager, ElevatedOutcome
|
|
121
|
+
export type { AuthError, AuthManager, ElevatedOutcome };
|
|
@@ -13,7 +13,7 @@ type BrowserTokenResult = {
|
|
|
13
13
|
* one retry after wiping the profile; `navigation_failed` is a network
|
|
14
14
|
* issue, not worth retrying).
|
|
15
15
|
*
|
|
16
|
-
*
|
|
16
|
+
* was previously `AccessToken | null`, which conflated
|
|
17
17
|
* "browser launch hung", "navigation broke", and "silent-SSO polling
|
|
18
18
|
* timed out" into a single null and made the error message inaccurate.
|
|
19
19
|
*/
|
|
@@ -69,7 +69,7 @@ type Ic3TokenResult = {
|
|
|
69
69
|
/**
|
|
70
70
|
* Combined outcome of capturing all four tokens (Teams basic / M365
|
|
71
71
|
* elevated / chatsvcagg substrate / IC3 substrate) inside one browser
|
|
72
|
-
* session.
|
|
72
|
+
* session. introduced this for the basic+elevated
|
|
73
73
|
* pair; chatsvcagg was added next; IC3 is the most recent leg, capturing
|
|
74
74
|
* the bearer Teams web uses for unbounded chat-history reads.
|
|
75
75
|
*
|
|
@@ -84,7 +84,7 @@ type BothTokensResult = {
|
|
|
84
84
|
readonly ic3: Ic3TokenResult;
|
|
85
85
|
/**
|
|
86
86
|
* Set when the Teams poll short-circuited because `freshCachedToken`
|
|
87
|
-
* found a token written by a concurrent process
|
|
87
|
+
* found a token written by a concurrent process. The caller
|
|
88
88
|
* must NOT persist this result — the cache is already the source of
|
|
89
89
|
* truth, and `refreshToken` is null here (persisting would clobber the
|
|
90
90
|
* winner's rotated refresh token).
|
|
@@ -92,7 +92,6 @@ type BothTokensResult = {
|
|
|
92
92
|
readonly fromCache?: true;
|
|
93
93
|
};
|
|
94
94
|
type BrowserAuth = {
|
|
95
|
-
acquireToken: (scopes: string[], startUrl: string) => Promise<BrowserTokenResult | null>;
|
|
96
95
|
/**
|
|
97
96
|
* Capture an "elevated" Graph access token by navigating to a
|
|
98
97
|
* different Microsoft web app whose first-party app identity is on
|
|
@@ -136,11 +135,11 @@ type BrowserAuth = {
|
|
|
136
135
|
*/
|
|
137
136
|
acquireIc3Token: () => Promise<Ic3TokenResult>;
|
|
138
137
|
/**
|
|
139
|
-
*
|
|
138
|
+
* capture BOTH tokens inside ONE browser session.
|
|
140
139
|
* After the Teams response listener intercepts the Teams token,
|
|
141
140
|
* navigate the SAME page to the elevated URL and harvest the
|
|
142
141
|
* M365ChatClient bearer from outgoing request headers. Cookies are
|
|
143
|
-
* live in memory, so federated SSO chains (e.g.
|
|
142
|
+
* live in memory, so federated SSO chains (e.g. third-party-IdP-fronted
|
|
144
143
|
* tenants) work without a second visible sign-in.
|
|
145
144
|
*
|
|
146
145
|
* Returns `teams: null` if no Teams token came back within the full
|
|
@@ -149,7 +148,9 @@ type BrowserAuth = {
|
|
|
149
148
|
* failed inside the same session — caller decides whether to surface
|
|
150
149
|
* the partial success.
|
|
151
150
|
*/
|
|
152
|
-
acquireBothTokens: (
|
|
151
|
+
acquireBothTokens: (teamsUrl: string, options?: {
|
|
152
|
+
skipCacheProbe?: boolean;
|
|
153
|
+
}) => Promise<BothTokensResult>;
|
|
153
154
|
close: () => Promise<void>;
|
|
154
155
|
};
|
|
155
156
|
type ResponseLike = {
|
|
@@ -199,7 +200,7 @@ type BrowserAuthConfig = {
|
|
|
199
200
|
readonly fs: FileSystem;
|
|
200
201
|
readonly trace?: TraceFn;
|
|
201
202
|
/**
|
|
202
|
-
*
|
|
203
|
+
* (login hang): probe for a fresh token that landed in the cache
|
|
203
204
|
* WHILE the browser capture is polling. AAD SPA refresh tokens rotate, so
|
|
204
205
|
* when two processes race, the loser's refresh fails and it falls into the
|
|
205
206
|
* full multi-minute browser dance — while the winner's fresh token sits in
|
|
@@ -210,7 +211,7 @@ type BrowserAuthConfig = {
|
|
|
210
211
|
/**
|
|
211
212
|
* User-visible progress sink (stderr in production). The browser capture
|
|
212
213
|
* can legitimately take minutes (federated SSO, interactive sign-in); these
|
|
213
|
-
* one-liners are what separates "waiting on the user" from "hung"
|
|
214
|
+
* one-liners are what separates "waiting on the user" from "hung".
|
|
214
215
|
*/
|
|
215
216
|
readonly onProgress?: (line: string) => void;
|
|
216
217
|
readonly profileDir?: string;
|
|
@@ -222,19 +223,19 @@ type BrowserAuthConfig = {
|
|
|
222
223
|
/**
|
|
223
224
|
* Deadline for the SILENT elevated-token recapture flow (no user
|
|
224
225
|
* interaction expected — persistent profile cookies do the SSO).
|
|
225
|
-
* Defaults to 20s. The audit (
|
|
226
|
+
* Defaults to 20s. The audit () flagged that reusing the
|
|
226
227
|
* 5-minute interactive `pollDeadlineMs` for this silent path made
|
|
227
228
|
* `list-chats` etc. hang for minutes when cookies were stale, blowing
|
|
228
229
|
* the LLM tool-call window. With a tight cap, the flow either yields
|
|
229
230
|
* a token quickly or fails with `auth_failed: elevated token capture
|
|
230
|
-
* timed out — run `ask-marcel login` to refresh.`
|
|
231
|
+
* timed out — run `ask-marcel-office login` to refresh.`
|
|
231
232
|
*/
|
|
232
233
|
readonly elevatedRecaptureTimeoutMs?: number;
|
|
233
234
|
/**
|
|
234
235
|
* Hard deadline on `launchPersistentContext` + `newPage` for the
|
|
235
236
|
* elevated capture path. Defaults to 15s. Distinct from
|
|
236
237
|
* `elevatedRecaptureTimeoutMs` so the error message can name which
|
|
237
|
-
* step hung — launch vs polling. Audit
|
|
238
|
+
* step hung — launch vs polling. Audit previously
|
|
238
239
|
* unguarded, so a hung Playwright launch (corrupt persistent profile
|
|
239
240
|
* with stale `Singleton*` locks, or a slow browser binary) would
|
|
240
241
|
* block the whole command indefinitely.
|
|
@@ -109,11 +109,37 @@ type TokenInfo = {
|
|
|
109
109
|
/**
|
|
110
110
|
* Seconds remaining until the cached token's `exp` claim — derived from
|
|
111
111
|
* `expiresAt - now`. Negative when the token has already expired. Absent
|
|
112
|
-
* when the JWT did not carry an `exp` claim.
|
|
113
|
-
* an LLM decide pre-emptively to run `ask-marcel login` (re-auth typically
|
|
112
|
+
* when the JWT did not carry an `exp` claim. lets
|
|
113
|
+
* an LLM decide pre-emptively to run `ask-marcel-office login` (re-auth typically
|
|
114
114
|
* worth doing under ~5 minutes) without parsing the ISO string itself.
|
|
115
115
|
*/
|
|
116
116
|
readonly expiresInSeconds: number | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* Whether the *persisted* elevated (M365ChatClient) token — the one the
|
|
119
|
+
* historical-version download / convert commands need — is present and still
|
|
120
|
+
* usable, plus its raw seconds-to-expiry (`undefined` when absent). `available`
|
|
121
|
+
* is `false` when the auth manager cannot introspect it. Lets `deep-scan`
|
|
122
|
+
* preflight elevated access in a fresh process instead of turning every
|
|
123
|
+
* version download into a `403`.
|
|
124
|
+
*/
|
|
125
|
+
readonly elevated: {
|
|
126
|
+
readonly available: boolean;
|
|
127
|
+
readonly expiresInSeconds: number | undefined;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* The two Teams-chat substrate tokens (chatsvcagg / ic3), same decode-only
|
|
131
|
+
* `{ available, expiresInSeconds }` shape as `elevated`. `login` reports all four
|
|
132
|
+
* tiers so a warm session can see every token's runway; both self-heal from the
|
|
133
|
+
* shared refresh token, so they are informational rather than a preflight gate.
|
|
134
|
+
*/
|
|
135
|
+
readonly chatsvcagg: {
|
|
136
|
+
readonly available: boolean;
|
|
137
|
+
readonly expiresInSeconds: number | undefined;
|
|
138
|
+
};
|
|
139
|
+
readonly ic3: {
|
|
140
|
+
readonly available: boolean;
|
|
141
|
+
readonly expiresInSeconds: number | undefined;
|
|
142
|
+
};
|
|
117
143
|
};
|
|
118
144
|
type FetchFn = (url: string, init?: RequestInit) => Promise<Response>;
|
|
119
145
|
declare const createGraphClient: (auth: AuthManager, fetchFn?: FetchFn) => GraphClient;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Translate Graph / substrate / CLI / validation errors into actionable hints.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* bare `error: ErrorInvalidIdMalformed: Id is
|
|
5
5
|
* malformed.` had no remedy for the LLM — it had to guess where the bad ID
|
|
6
6
|
* came from. This module is the centralised "what should I do about this"
|
|
7
7
|
* lookup: pattern-match the error code (or, as a fallback, a substring of
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
* `--output text` (as `hint:` / `source:` lines under the existing `error:`
|
|
13
13
|
* line).
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
15
|
+
* the four error-envelope variants are
|
|
16
|
+
* - `graph` — public Microsoft Graph API at /v1.0/
|
|
17
|
+
* - `substrate` — Microsoft-internal chat substrates (chatsvcagg / IC3).
|
|
18
|
+
* Tagged at the infra layer with `substrateHttp{N}_{name}`.
|
|
19
|
+
* - `cli` — CLI itself (Commander parser, CLI rewrites of Graph
|
|
20
|
+
* errors via `cli_rewrite_*` and `cli_reject_*` codes)
|
|
21
|
+
* - `validation` — Zod schema validation from use-cases (no `code` — pure
|
|
22
|
+
* message-pattern fallback)
|
|
23
23
|
*
|
|
24
24
|
* Rule precedence: specific code matchers run FIRST, then message-pattern
|
|
25
25
|
* fallbacks. The generic-validation rule sits LAST so it never overrides a
|
|
@@ -7,7 +7,7 @@ import { type ODataKey } from './odata-query.js';
|
|
|
7
7
|
* passthroughs at all). `defaultSelect`, when set and the user did NOT pass
|
|
8
8
|
* `--select`, is injected into the OData query string so default invocations
|
|
9
9
|
* return a slim projection instead of a 50 KB resource. User-supplied
|
|
10
|
-
* `--select` always wins.
|
|
10
|
+
* `--select` always wins. pairs the `list-mail-attachments`
|
|
11
11
|
* pattern with the builder layer so the 6 heaviest endpoints stop returning
|
|
12
12
|
* the full Graph resource by default.
|
|
13
13
|
*/
|
|
@@ -52,7 +52,7 @@ type CommandOptionMeta = {
|
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
54
54
|
* A positional argument (i.e. NOT a `--flag`). Used today only for the
|
|
55
|
-
* `docs` lifecycle command (`ask-marcel docs <command>`) but kept as its
|
|
55
|
+
* `docs` lifecycle command (`ask-marcel-office docs <command>`) but kept as its
|
|
56
56
|
* own field so the manifest never claims a positional is a flag. An LLM
|
|
57
57
|
* consumer reading `help-json` can branch on the presence of
|
|
58
58
|
* `positionalArguments` to know to skip the `--` prefix.
|
|
@@ -100,7 +100,7 @@ type CommandMeta = {
|
|
|
100
100
|
readonly paginationStrategy?: PaginationStrategy;
|
|
101
101
|
/**
|
|
102
102
|
* Graph permission scopes the endpoint requires. The basic Teams web-client
|
|
103
|
-
* token grants ~30 scopes (run `ask-marcel scopes-check` to see). Commands
|
|
103
|
+
* token grants ~30 scopes (run `ask-marcel-office scopes-check` to see). Commands
|
|
104
104
|
* with unmet scopes return `403 Forbidden: Missing scope` at the wire. Use
|
|
105
105
|
* this for pre-flight checks rather than failing on-the-wire. Optional —
|
|
106
106
|
* populated only on commands where the audit confirmed a scope-failure
|
|
@@ -120,7 +120,7 @@ type CommandMeta = {
|
|
|
120
120
|
* captured at login from `teams.microsoft.com`) — the Teams chat-content
|
|
121
121
|
* commands. Like `needsElevatedToken`, an LLM should check this before
|
|
122
122
|
* invoking and warm up an interactive `login`; a headless or stale session
|
|
123
|
-
* times out on these (the non-interactive silent-SSO limitation,
|
|
123
|
+
* times out on these (the non-interactive silent-SSO limitation, ).
|
|
124
124
|
*/
|
|
125
125
|
readonly needsSubstrateToken?: true;
|
|
126
126
|
/**
|
|
@@ -128,7 +128,7 @@ type CommandMeta = {
|
|
|
128
128
|
* or `{contentType, size, text}`) and is therefore a valid target for the
|
|
129
129
|
* global `--output-path` flag. Used by the CLI composition to derive the
|
|
130
130
|
* rejection-message whitelist from the manifest rather than hand-keeping it
|
|
131
|
-
* as a string literal. Audit
|
|
131
|
+
* as a string literal. Audit .
|
|
132
132
|
*/
|
|
133
133
|
readonly producesBytes?: true;
|
|
134
134
|
/**
|
|
@@ -157,7 +157,7 @@ type CommandMeta = {
|
|
|
157
157
|
* substrate (chatsvcagg / IC3) that is not in the public Graph API and can
|
|
158
158
|
* break on a Teams web-client update — the docstring "Best-effort, may break
|
|
159
159
|
* on Microsoft client updates" warnings now have a structured pair.
|
|
160
|
-
*
|
|
160
|
+
*
|
|
161
161
|
*/
|
|
162
162
|
readonly stability?: 'experimental';
|
|
163
163
|
};
|
|
@@ -29,6 +29,10 @@ declare const schema: z.ZodObject<{
|
|
|
29
29
|
true: "true";
|
|
30
30
|
false: "false";
|
|
31
31
|
}>>;
|
|
32
|
+
includeImages: z.ZodOptional<z.ZodEnum<{
|
|
33
|
+
true: "true";
|
|
34
|
+
false: "false";
|
|
35
|
+
}>>;
|
|
32
36
|
maxCells: z.ZodOptional<z.ZodString>;
|
|
33
37
|
}, z.core.$strip>;
|
|
34
38
|
declare const executeLocal: (fs: FileSystem, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Command, CommandMeta } from './command-types.js';
|
|
3
|
+
declare const schema: z.ZodObject<{
|
|
4
|
+
forwardMessageId: z.ZodString;
|
|
5
|
+
toRecipients: z.ZodString;
|
|
6
|
+
ccRecipients: z.ZodOptional<z.ZodString>;
|
|
7
|
+
bodyContent: z.ZodString;
|
|
8
|
+
subject: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
declare const execute: Command['execute'];
|
|
11
|
+
declare const meta: CommandMeta;
|
|
12
|
+
export { execute, meta, schema };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Command, CommandMeta } from './command-types.js';
|
|
3
|
+
declare const schema: z.ZodObject<{
|
|
4
|
+
replyToMessageId: z.ZodString;
|
|
5
|
+
bodyContent: z.ZodString;
|
|
6
|
+
subject: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
declare const execute: Command['execute'];
|
|
9
|
+
declare const meta: CommandMeta;
|
|
10
|
+
export { execute, meta, schema };
|
|
@@ -13,7 +13,7 @@ export type DocsError = {
|
|
|
13
13
|
* `scopesRequired` — everything the LLM only needs once it's already decided
|
|
14
14
|
* to invoke. `stability` is kept (it's a discovery-time concern: LLMs prefer
|
|
15
15
|
* stable siblings when they exist, so they need to see the tag at discovery
|
|
16
|
-
* time, not after a second full-manifest fetch).
|
|
16
|
+
* time, not after a second full-manifest fetch). /§6.
|
|
17
17
|
*/
|
|
18
18
|
export type TerseManifestEntry = {
|
|
19
19
|
readonly name: string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Command, CommandMeta } from './command-types.js';
|
|
3
|
+
declare const schema: z.ZodObject<{
|
|
4
|
+
schedules: z.ZodString;
|
|
5
|
+
startDateTime: z.ZodPipe<z.ZodString, z.ZodTransform<import("../../domain/iso-datetime.js").IsoDateTime, string>>;
|
|
6
|
+
endDateTime: z.ZodPipe<z.ZodString, z.ZodTransform<import("../../domain/iso-datetime.js").IsoDateTime, string>>;
|
|
7
|
+
availabilityViewInterval: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
declare const execute: Command['execute'];
|
|
10
|
+
declare const meta: CommandMeta;
|
|
11
|
+
export { execute, meta, schema };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Result } from '../../domain/result.js';
|
|
2
2
|
import type { GraphError } from '../../infra/graph-client.js';
|
|
3
|
+
import type { MediaEnvelope } from './media-files.js';
|
|
3
4
|
/**
|
|
4
5
|
* Shared by extract-drive-item-images and extract-mail-attachment-images: pick the
|
|
5
6
|
* extractor for the file's extension and run it, or return a 415 whose tail
|
|
6
7
|
* (`fetchHint`) names the caller's raw-bytes route. Both commands fetch / decode the
|
|
7
8
|
* bytes first, then hand them here, so the dispatch + media envelope live in one place.
|
|
8
9
|
*/
|
|
9
|
-
declare const extractImagesFromBytes: (bytes: Uint8Array, name: string, fetchHint: string) => Promise<Result<
|
|
10
|
+
declare const extractImagesFromBytes: (bytes: Uint8Array, name: string, fetchHint: string) => Promise<Result<MediaEnvelope, GraphError>>;
|
|
10
11
|
export { extractImagesFromBytes };
|
|
@@ -6,7 +6,7 @@ import { z } from 'zod';
|
|
|
6
6
|
* compose this into their schemas in place of `z.string().min(1)`; the
|
|
7
7
|
* URL-builder sees the already-resolved canonical ISO form.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* removes the manual ISO arithmetic an LLM had to do
|
|
10
10
|
* to ask "what changed this week" against `list-calendar-view`. Type
|
|
11
11
|
* inference is left to Zod so the calendar commands' shape signatures stay
|
|
12
12
|
* compatible with `buildListCommand`'s `ZodRawShape` constraint.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type RefreshRoute = 'automatic' | 'interactive';
|
|
2
|
+
type TokenTier = {
|
|
3
|
+
readonly available: boolean;
|
|
4
|
+
readonly expiresInSeconds: number | undefined;
|
|
5
|
+
};
|
|
6
|
+
type TokenView = {
|
|
7
|
+
available: boolean;
|
|
8
|
+
expiresInSeconds?: number;
|
|
9
|
+
refresh: RefreshRoute;
|
|
10
|
+
reason?: string;
|
|
11
|
+
};
|
|
12
|
+
type LoginStatus = {
|
|
13
|
+
status: 'authenticated';
|
|
14
|
+
tokens: {
|
|
15
|
+
basic: TokenView;
|
|
16
|
+
elevated: TokenView;
|
|
17
|
+
chatsvcagg: TokenView;
|
|
18
|
+
ic3: TokenView;
|
|
19
|
+
};
|
|
20
|
+
hint: string;
|
|
21
|
+
};
|
|
22
|
+
type LoginStatusInput = {
|
|
23
|
+
readonly basicExpiresInSeconds: number | undefined;
|
|
24
|
+
readonly elevated: TokenTier;
|
|
25
|
+
readonly chatsvcagg: TokenTier;
|
|
26
|
+
readonly ic3: TokenTier;
|
|
27
|
+
readonly elevatedFailureReason?: string;
|
|
28
|
+
};
|
|
29
|
+
declare const buildLoginStatus: (input: LoginStatusInput) => LoginStatus;
|
|
30
|
+
export { buildLoginStatus };
|
|
31
|
+
export type { LoginStatus, LoginStatusInput };
|
|
@@ -2,5 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import type { Result } from '../../domain/result.js';
|
|
3
3
|
import type { AuthManager } from '../../infra/auth.js';
|
|
4
4
|
declare const schema: z.ZodObject<{}, z.core.$strict>;
|
|
5
|
-
declare const execute: (auth: AuthManager
|
|
5
|
+
declare const execute: (auth: AuthManager, options?: {
|
|
6
|
+
force?: boolean;
|
|
7
|
+
}) => Promise<Result<string, import("../../infra/auth.js").AuthError>>;
|
|
6
8
|
export { execute, schema };
|
|
@@ -5,11 +5,11 @@ import { type InlineAttachment } from './inline-image-embedder.js';
|
|
|
5
5
|
* Orchestrate the four steps that turn a Graph `?format=html` content
|
|
6
6
|
* call into a markdown envelope:
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* 1. getBinary(contentPath)
|
|
9
|
+
* 2. if Graph returned a 302 downloadUrl, follow via fetchUrl (host
|
|
10
|
+
* allow-list enforced inside fetchUrl, Hardening #3)
|
|
11
|
+
* 3. embedInlineImages over any cid: refs (Hardening #1: image/* only)
|
|
12
|
+
* 4. htmlToMarkdown via turndown
|
|
13
13
|
*
|
|
14
14
|
* Returns `{ contentType: 'text/markdown', size, text }` on success.
|
|
15
15
|
*/
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* `--drive-id` description for every generic OneDrive / SharePoint drive-item
|
|
3
3
|
* command. Always points the caller at how to obtain a drive id.
|
|
4
4
|
*/
|
|
5
|
-
export declare const DRIVE_ID_DESCRIPTION = "Microsoft Graph drive ID. Use `ask-marcel list-drives` for the personal OneDrive, or `ask-marcel list-sharepoint-site-drives --site-id <id>` for a SharePoint document library.";
|
|
5
|
+
export declare const DRIVE_ID_DESCRIPTION = "Microsoft Graph drive ID. Use `ask-marcel-office list-drives` for the personal OneDrive, or `ask-marcel-office list-sharepoint-site-drives --site-id <id>` for a SharePoint document library.";
|
|
@@ -11,10 +11,10 @@ import type { FileSystem } from '../ports/filesystem.js';
|
|
|
11
11
|
* Two recognized inline shapes — both produced by `inlineBinary` and
|
|
12
12
|
* `office-to-markdown`:
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* 1. `{ contentType, size, base64 }` — written via `fs.writeBytes`,
|
|
15
|
+
* with `base64` replaced by `savedTo`.
|
|
16
|
+
* 2. `{ contentType, size, text }` — written via `fs.writeText`,
|
|
17
|
+
* with `text` replaced by `savedTo`.
|
|
18
18
|
*
|
|
19
19
|
* Anything else (plain JSON gets, error envelopes, etc.) returns
|
|
20
20
|
* `no_inlined_bytes` so the CLI can surface a clear error rather than
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a comma-separated recipient string into Microsoft Graph address
|
|
3
|
+
* objects. Shared by the mail-draft write commands (create-mail-draft,
|
|
4
|
+
* update-mail-draft, create-forward-draft) so the split/trim/empty-drop
|
|
5
|
+
* behaviour stays identical across all three. Whitespace around each address
|
|
6
|
+
* is trimmed and empty segments (leading, trailing, or doubled commas) are
|
|
7
|
+
* dropped, so `"a@x.com, , b@x.com,"` yields exactly two recipients.
|
|
8
|
+
*/
|
|
9
|
+
declare const parseRecipients: (csv: string) => Array<{
|
|
10
|
+
emailAddress: {
|
|
11
|
+
address: string;
|
|
12
|
+
};
|
|
13
|
+
}>;
|
|
14
|
+
export { parseRecipients };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Result } from '../../domain/result.js';
|
|
2
2
|
import type { GraphError } from '../../infra/graph-client.js';
|
|
3
|
+
import type { MediaEnvelope } from './media-files.js';
|
|
3
4
|
/**
|
|
4
5
|
* Shared "unzip + convert every contained file" core behind
|
|
5
6
|
* `convert-drive-item-zip` (a OneDrive / SharePoint .zip),
|
|
@@ -8,7 +9,7 @@ import type { GraphError } from '../../infra/graph-client.js';
|
|
|
8
9
|
* `bytesToMarkdown` dispatch the markdown commands use; an entry the dispatch
|
|
9
10
|
* can't convert (image, binary, nested archive, scanned PDF) is LISTED with a
|
|
10
11
|
* note instead of failing the whole archive. Notes use the container-neutral
|
|
11
|
-
* NESTED_HINTS
|
|
12
|
+
* NESTED_HINTS: entries live INSIDE the zip, so caller-specific
|
|
12
13
|
* sibling-command pointers (`extract-drive-item-images`, …) cannot reach them.
|
|
13
14
|
*/
|
|
14
15
|
declare const MAX_ENTRIES = 100;
|
|
@@ -18,6 +19,7 @@ type FileResult = {
|
|
|
18
19
|
readonly size?: number;
|
|
19
20
|
readonly text?: string;
|
|
20
21
|
readonly note?: string;
|
|
22
|
+
readonly images?: MediaEnvelope['media'];
|
|
21
23
|
};
|
|
22
24
|
type ZipArchiveResult = {
|
|
23
25
|
readonly count: number;
|
|
@@ -25,6 +27,6 @@ type ZipArchiveResult = {
|
|
|
25
27
|
readonly totalEntries?: number;
|
|
26
28
|
readonly files: ReadonlyArray<FileResult>;
|
|
27
29
|
};
|
|
28
|
-
declare const convertZipArchive: (bytes: Uint8Array, includeMetadata: boolean) => Promise<Result<ZipArchiveResult, GraphError>>;
|
|
30
|
+
declare const convertZipArchive: (bytes: Uint8Array, includeMetadata: boolean, includeImages?: boolean) => Promise<Result<ZipArchiveResult, GraphError>>;
|
|
29
31
|
export { convertZipArchive, MAX_ENTRIES };
|
|
30
32
|
export type { FileResult, ZipArchiveResult };
|
|
@@ -19,7 +19,7 @@ export type FileSystem = {
|
|
|
19
19
|
readonly writeBytes: (path: string, bytes: Uint8Array) => Promise<Result<void, FileSystemError>>;
|
|
20
20
|
/**
|
|
21
21
|
* Restrict a file's permission bits (e.g. 0o600 on the token cache so
|
|
22
|
-
* other local users cannot read cached secrets —
|
|
22
|
+
* other local users cannot read cached secrets — ).
|
|
23
23
|
*/
|
|
24
24
|
readonly chmod: (path: string, mode: number) => Promise<Result<void, FileSystemError>>;
|
|
25
25
|
readonly deleteIfExists: (path: string) => Promise<Result<void, FileSystemError>>;
|