ask-marcel-office-cli 2.1.0 → 2.3.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 +283 -0
- package/README.md +178 -119
- package/dist/cli.js +44725 -27155
- package/dist/commands.json +406 -734
- package/dist/composition/build-deps.d.ts +8 -0
- package/dist/composition/mcp.d.ts +20 -0
- package/dist/composition/run-registry-command.d.ts +43 -0
- package/dist/domain/tenant-id.d.ts +9 -0
- package/dist/domain/utilities/spo-tenant.d.ts +20 -0
- package/dist/index.js +2831 -1833
- package/dist/infra/auth.d.ts +36 -14
- package/dist/infra/browser-auth.d.ts +7 -2
- package/dist/infra/graph-client.d.ts +52 -16
- package/dist/presenter/graph-cursor.d.ts +2 -0
- package/dist/presenter/output.d.ts +2 -2
- package/dist/presenter/render-to-string.d.ts +47 -0
- package/dist/use-cases/commands/build-command.d.ts +19 -2
- package/dist/use-cases/commands/command-types.d.ts +17 -31
- package/dist/use-cases/commands/convert-calendar-event-attachment-to-markdown.d.ts +4 -0
- package/dist/use-cases/commands/{convert-drive-item-zip.d.ts → convert-drive-item-zip-to-markdown.d.ts} +5 -0
- package/dist/use-cases/commands/{convert-local-file.d.ts → convert-local-file-to-markdown.d.ts} +4 -0
- package/dist/use-cases/commands/convert-mail-attachment-to-markdown.d.ts +10 -2
- package/dist/use-cases/commands/{convert-mail-attachment-zip.d.ts → convert-mail-attachment-zip-to-markdown.d.ts} +5 -1
- package/dist/use-cases/commands/convert-mail-to-markdown.d.ts +35 -1
- package/dist/use-cases/commands/create-forward-draft.d.ts +5 -1
- package/dist/use-cases/commands/create-reply-draft.d.ts +9 -1
- package/dist/use-cases/commands/docs-render.d.ts +0 -1
- package/dist/use-cases/commands/download-drive-item-as-markdown.d.ts +7 -2
- package/dist/use-cases/commands/download-drive-item-as-pdf.d.ts +1 -0
- package/dist/use-cases/commands/download-drive-item-content.d.ts +1 -0
- package/dist/use-cases/commands/draft-comment-splicer.d.ts +36 -0
- package/dist/use-cases/commands/draft-dedup.d.ts +18 -0
- package/dist/use-cases/commands/draft-response.d.ts +4 -0
- package/dist/use-cases/commands/extract-drive-item-images.d.ts +1 -0
- package/dist/use-cases/commands/extract-local-file-images.d.ts +1 -1
- package/dist/use-cases/commands/fetch-raw-bytes.d.ts +13 -0
- package/dist/use-cases/commands/find-mail-drafts.d.ts +9 -0
- package/dist/use-cases/commands/get-mail-signature.d.ts +8 -0
- package/dist/use-cases/commands/get-user.d.ts +10 -0
- package/dist/use-cases/commands/inline-image-embedder.d.ts +2 -1
- package/dist/use-cases/commands/list-mail-folder-messages-delta.d.ts +10 -2
- package/dist/use-cases/commands/login-status.d.ts +9 -27
- package/dist/use-cases/commands/login.d.ts +21 -0
- package/dist/use-cases/commands/mail-message-select.d.ts +1 -0
- package/dist/use-cases/commands/mail-quote-stripper.d.ts +16 -15
- package/dist/use-cases/commands/markdown-dispatch.d.ts +2 -1
- package/dist/use-cases/commands/msg-to-markdown.d.ts +10 -1
- package/dist/use-cases/commands/odata-query.d.ts +15 -1
- package/dist/use-cases/commands/office-to-markdown.d.ts +1 -0
- package/dist/use-cases/commands/read-mail-attachment.d.ts +4 -0
- package/dist/use-cases/commands/reject-unknown-params.d.ts +16 -0
- package/dist/use-cases/commands/resolve-command.d.ts +23 -0
- package/dist/use-cases/commands/search-all-files.d.ts +8 -0
- package/dist/use-cases/commands/search-escape.d.ts +23 -0
- package/dist/use-cases/commands/search-onenote-pages.d.ts +1 -1
- package/dist/use-cases/commands/signature-extractor.d.ts +2 -0
- package/dist/use-cases/commands/tenant-option.d.ts +44 -0
- package/dist/use-cases/commands/update-mail-draft.d.ts +5 -0
- package/dist/use-cases/commands/zip-archive-to-markdown.d.ts +10 -5
- package/dist/use-cases/ports/filesystem.d.ts +1 -1
- package/docs/COMMANDS.md +38 -33
- package/docs/USAGE.md +65 -7
- package/package.json +2 -1
package/dist/infra/auth.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AccessToken } from '../domain/access-token.js';
|
|
2
2
|
import type { Result } from '../domain/result.js';
|
|
3
|
+
import type { TenantId } from '../domain/tenant-id.js';
|
|
3
4
|
import type { FileSystem } from '../use-cases/ports/filesystem.js';
|
|
4
5
|
import type { Logger } from '../use-cases/ports/logger.js';
|
|
5
6
|
import type { BrowserAuth, ElevatedFailureReason } from './browser-auth.js';
|
|
@@ -24,6 +25,11 @@ type ElevatedOutcome = {
|
|
|
24
25
|
captured: false;
|
|
25
26
|
reason: ElevatedFailureReason | 'unknown_error';
|
|
26
27
|
};
|
|
28
|
+
type CachedTierInfo = {
|
|
29
|
+
readonly available: boolean;
|
|
30
|
+
readonly expiresInSeconds: number | undefined;
|
|
31
|
+
readonly scopes: ReadonlyArray<string>;
|
|
32
|
+
};
|
|
27
33
|
type AuthManager = {
|
|
28
34
|
getAccessToken: (options?: {
|
|
29
35
|
force?: boolean;
|
|
@@ -34,6 +40,14 @@ type AuthManager = {
|
|
|
34
40
|
* via headless Playwright. Used by the 3 historical-version commands.
|
|
35
41
|
*/
|
|
36
42
|
getElevatedAccessToken: () => Promise<Result<AccessToken, AuthError>>;
|
|
43
|
+
/**
|
|
44
|
+
* Returns a Graph token issued by a PARTNER tenant's authority, for a user
|
|
45
|
+
* who is a guest there. Without it, every call against that tenant's
|
|
46
|
+
* SharePoint dies at `401 invalidAudienceUri` — home-tenant Graph cannot mint
|
|
47
|
+
* an SPO token for a foreign tenant. Cache -> headless redemption of the
|
|
48
|
+
* shared refresh token; never a browser.
|
|
49
|
+
*/
|
|
50
|
+
getGuestAccessToken: (tenantId: TenantId) => Promise<Result<AccessToken, AuthError>>;
|
|
37
51
|
/**
|
|
38
52
|
* Returns a chatsvcagg-audience token (same Teams web client identity
|
|
39
53
|
* as `getAccessToken`, but issued for the chatsvcagg resource). Falls
|
|
@@ -81,26 +95,32 @@ type AuthManager = {
|
|
|
81
95
|
* Optional: only the real manager implements it; a minimal fake omits it
|
|
82
96
|
* and callers treat that as unavailable. Never captures or refreshes.
|
|
83
97
|
*/
|
|
84
|
-
getCachedElevatedInfo?: () => Promise<
|
|
85
|
-
available: boolean;
|
|
86
|
-
expiresInSeconds: number | undefined;
|
|
87
|
-
}>;
|
|
98
|
+
getCachedElevatedInfo?: () => Promise<CachedTierInfo>;
|
|
88
99
|
/**
|
|
89
100
|
* Same decode-only preflight as `getCachedElevatedInfo`, for the chatsvcagg /
|
|
90
101
|
* ic3 Teams-chat substrate tokens. `login`'s four-token status and
|
|
91
102
|
* `scopes-check` read these; a minimal fake omits them and callers treat that
|
|
92
103
|
* as unavailable.
|
|
93
104
|
*/
|
|
94
|
-
getCachedChatsvcaggInfo?: () => Promise<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
getCachedChatsvcaggInfo?: () => Promise<CachedTierInfo>;
|
|
106
|
+
getCachedIc3Info?: () => Promise<CachedTierInfo>;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Command names quoted in the secondary-token error messages, per token kind.
|
|
110
|
+
* The composition root derives these from the command registry
|
|
111
|
+
* (`needsElevatedToken` / `needsSubstrateToken` flags) and injects them; the
|
|
112
|
+
* defaults below are the corrected registry sets at the time of writing, so
|
|
113
|
+
* direct `createAuthManagerFromApi` callers still get accurate messages. The
|
|
114
|
+
* registry sets are pinned in meta.test.ts and the wiring in
|
|
115
|
+
* build-deps.test.ts, so drift surfaces there, not in a stale user message
|
|
116
|
+
* (the old hardcoded elevated list omitted `get-user`).
|
|
117
|
+
*/
|
|
118
|
+
type SecondaryTokenCommands = {
|
|
119
|
+
readonly elevated: ReadonlyArray<string>;
|
|
120
|
+
readonly chatsvcagg: ReadonlyArray<string>;
|
|
121
|
+
readonly ic3: ReadonlyArray<string>;
|
|
102
122
|
};
|
|
103
|
-
declare const createAuthManagerFromApi: (browserAuth: BrowserAuth, cachePath: string, browserProfileDir: string, logger: Logger, fs: FileSystem, recaptureSecondaryViaBrowser?: boolean) => AuthManager;
|
|
123
|
+
declare const createAuthManagerFromApi: (browserAuth: BrowserAuth, cachePath: string, browserProfileDir: string, logger: Logger, fs: FileSystem, recaptureSecondaryViaBrowser?: boolean, secondaryTokenCommands?: SecondaryTokenCommands, acquireBasicViaBrowser?: boolean) => AuthManager;
|
|
104
124
|
/**
|
|
105
125
|
* Probe the token cache for a fresh access token. Handed to the browser
|
|
106
126
|
* capture so its poll loop can short-circuit the multi-minute dance
|
|
@@ -116,6 +136,8 @@ declare const createAuthManager: (deps: {
|
|
|
116
136
|
fs?: FileSystem;
|
|
117
137
|
browserProfileDir?: string;
|
|
118
138
|
recaptureSecondaryViaBrowser?: boolean;
|
|
139
|
+
secondaryTokenCommands?: SecondaryTokenCommands;
|
|
140
|
+
acquireBasicViaBrowser?: boolean;
|
|
119
141
|
}) => AuthManager;
|
|
120
142
|
export { createAuthManager, createAuthManagerFromApi, createFreshCachedTokenProbe, stderrProgress };
|
|
121
|
-
export type { AuthError, AuthManager, ElevatedOutcome };
|
|
143
|
+
export type { AuthError, AuthManager, CachedTierInfo, ElevatedOutcome, SecondaryTokenCommands };
|
|
@@ -97,8 +97,13 @@ type BrowserAuth = {
|
|
|
97
97
|
* different Microsoft web app whose first-party app identity is on
|
|
98
98
|
* Microsoft's allow-list for ODSP `logicalPermissions` (the scope our
|
|
99
99
|
* Teams web client token lacks for historical-version stream
|
|
100
|
-
* content).
|
|
101
|
-
*
|
|
100
|
+
* content). Launches a HEADED browser (`launchContext(false)`) and
|
|
101
|
+
* relies, best-effort, on the persistent profile's cookies to complete
|
|
102
|
+
* sign-in silently. This is NOT guaranteed: on tenants that do not
|
|
103
|
+
* persist SSO cookies (or once they lapse) the navigation lands on a
|
|
104
|
+
* sign-in wall and the capture times out (verified headed AND headless
|
|
105
|
+
* 2026-07-19). That is why it stays headed and why the caller treats a
|
|
106
|
+
* miss as non-fatal and points the user at an interactive `login`.
|
|
102
107
|
*
|
|
103
108
|
* Returns a discriminated union so the caller can distinguish the three
|
|
104
109
|
* failure modes (browser-launch hang, navigation failure, silent-SSO
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Result } from '../domain/result.js';
|
|
2
2
|
import type { AuthManager } from '../infra/auth.js';
|
|
3
|
+
import type { TenantId } from '../domain/tenant-id.js';
|
|
3
4
|
type GraphError = {
|
|
4
5
|
type: 'api_error';
|
|
5
6
|
status: number;
|
|
@@ -36,6 +37,34 @@ type GraphClient = {
|
|
|
36
37
|
* elevated token).
|
|
37
38
|
*/
|
|
38
39
|
getElevated: (path: string) => Promise<Result<unknown, GraphError>>;
|
|
40
|
+
/**
|
|
41
|
+
* JSON-GET signed with a PARTNER tenant's guest token instead of the home
|
|
42
|
+
* token. Required for any path that touches a tenant the user is only a guest
|
|
43
|
+
* in: home-tenant Graph cannot mint a SharePoint token for a foreign tenant,
|
|
44
|
+
* so those calls die at `401 invalidAudienceUri` no matter which home tier
|
|
45
|
+
* signs them.
|
|
46
|
+
*
|
|
47
|
+
* Get the `tenantId` from `resolve-drive-share-link` (it discovers it from the
|
|
48
|
+
* sharing URL) or from the caller's `--tenant-id`.
|
|
49
|
+
*/
|
|
50
|
+
getGuest: (path: string, tenantId: TenantId) => Promise<Result<unknown, GraphError>>;
|
|
51
|
+
/**
|
|
52
|
+
* Binary twin of `getGuest`: follows the Graph 302 to the partner tenant's CDN
|
|
53
|
+
* and returns the bytes. The `fetchUrl` allow-list already admits any
|
|
54
|
+
* `*.sharepoint.com` / `*.svc.ms` host, so a partner tenant's download URL
|
|
55
|
+
* needs no special casing.
|
|
56
|
+
*/
|
|
57
|
+
getBinaryGuest: (path: string, tenantId: TenantId) => Promise<Result<unknown, GraphError>>;
|
|
58
|
+
/**
|
|
59
|
+
* Resolves a SharePoint host to the Entra tenant that owns it, via the tenant's
|
|
60
|
+
* public OIDC discovery document. Unauthenticated: it asks "who owns this
|
|
61
|
+
* host?", not "what may I read?".
|
|
62
|
+
*
|
|
63
|
+
* This is what makes a bare sharing URL enough to cross tenants — the URL
|
|
64
|
+
* carries the host, the host names the tenant, and the tenant is the one thing
|
|
65
|
+
* `driveId` + `itemId` do not tell you.
|
|
66
|
+
*/
|
|
67
|
+
discoverTenantId: (spoHost: string) => Promise<Result<TenantId, GraphError>>;
|
|
39
68
|
/**
|
|
40
69
|
* JSON-GET against the Teams chat substrate (post-2026-05:
|
|
41
70
|
* `teams.microsoft.com/api/csa/<region>/api/v{N}/...` — see
|
|
@@ -102,6 +131,23 @@ type GraphClient = {
|
|
|
102
131
|
*/
|
|
103
132
|
getCachedTokenInfo: () => Promise<Result<TokenInfo, GraphError>>;
|
|
104
133
|
};
|
|
134
|
+
/**
|
|
135
|
+
* Decode-only status for one non-basic token tier: availability, remaining runway,
|
|
136
|
+
* the scopes granted to that token (decoded from its `scp`), and how it refreshes
|
|
137
|
+
* (`automatic` = rides the shared refresh token; `interactive` = elevated, needs a login).
|
|
138
|
+
*/
|
|
139
|
+
type TokenTierInfo = {
|
|
140
|
+
readonly available: boolean;
|
|
141
|
+
readonly expiresInSeconds: number | undefined;
|
|
142
|
+
readonly scopes: ReadonlyArray<string>;
|
|
143
|
+
readonly refresh: 'automatic' | 'interactive';
|
|
144
|
+
/**
|
|
145
|
+
* Present ONLY when `available` is `false`: a one-line, jargon-free reason the
|
|
146
|
+
* tier is absent + how to restore it. Stops the empty `scopes: []` on a missing
|
|
147
|
+
* token from reading as a bug. Omitted entirely when the token is available.
|
|
148
|
+
*/
|
|
149
|
+
readonly reason?: string;
|
|
150
|
+
};
|
|
105
151
|
type TokenInfo = {
|
|
106
152
|
readonly scopes: ReadonlyArray<string>;
|
|
107
153
|
readonly audience: string | undefined;
|
|
@@ -122,24 +168,14 @@ type TokenInfo = {
|
|
|
122
168
|
* preflight elevated access in a fresh process instead of turning every
|
|
123
169
|
* version download into a `403`.
|
|
124
170
|
*/
|
|
125
|
-
readonly elevated:
|
|
126
|
-
readonly available: boolean;
|
|
127
|
-
readonly expiresInSeconds: number | undefined;
|
|
128
|
-
};
|
|
171
|
+
readonly elevated: TokenTierInfo;
|
|
129
172
|
/**
|
|
130
|
-
* The two Teams-chat substrate tokens (chatsvcagg / ic3), same
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* shared refresh token, so they are informational rather than a preflight gate.
|
|
173
|
+
* The two Teams-chat substrate tokens (chatsvcagg / ic3), same `TokenTierInfo`
|
|
174
|
+
* shape as `elevated`. Both self-heal from the shared refresh token (refresh:
|
|
175
|
+
* automatic), so they are informational rather than a preflight gate.
|
|
134
176
|
*/
|
|
135
|
-
readonly chatsvcagg:
|
|
136
|
-
|
|
137
|
-
readonly expiresInSeconds: number | undefined;
|
|
138
|
-
};
|
|
139
|
-
readonly ic3: {
|
|
140
|
-
readonly available: boolean;
|
|
141
|
-
readonly expiresInSeconds: number | undefined;
|
|
142
|
-
};
|
|
177
|
+
readonly chatsvcagg: TokenTierInfo;
|
|
178
|
+
readonly ic3: TokenTierInfo;
|
|
143
179
|
};
|
|
144
180
|
type FetchFn = (url: string, init?: RequestInit) => Promise<Response>;
|
|
145
181
|
declare const createGraphClient: (auth: AuthManager, fetchFn?: FetchFn) => GraphClient;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Logger } from '../use-cases/ports/logger.js';
|
|
2
2
|
import type { ErrorSource } from './error-hints.js';
|
|
3
|
-
type OutputFormat
|
|
4
|
-
declare const render: (data: unknown, logger: Logger, format: OutputFormat) => void;
|
|
3
|
+
import type { OutputFormat, SizeHintContext } from './render-to-string.js';
|
|
4
|
+
declare const render: (data: unknown, logger: Logger, format: OutputFormat, context?: SizeHintContext) => void;
|
|
5
5
|
declare const renderError: (message: string, format: OutputFormat, errorCode?: string, explicitSource?: ErrorSource, retryAfterSeconds?: number) => void;
|
|
6
6
|
export { render, renderError };
|
|
7
7
|
export type { OutputFormat };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ErrorSource } from './error-hints.js';
|
|
2
|
+
type OutputFormat = 'text' | 'json';
|
|
3
|
+
/**
|
|
4
|
+
* Which front end the caller is on. It changes what a remedy can even BE: a
|
|
5
|
+
* terminal caller can redirect stdout to a file, an MCP client cannot (it has
|
|
6
|
+
* no shell), and the `--output-path` flag reaches MCP as an `outputPath` tool
|
|
7
|
+
* param rather than a flag.
|
|
8
|
+
*/
|
|
9
|
+
type RenderSurface = 'cli' | 'mcp';
|
|
10
|
+
/**
|
|
11
|
+
* What the presenter needs in order to name a remedy the caller can actually
|
|
12
|
+
* use. Built in composition (which owns the command manifest); omitted by the
|
|
13
|
+
* renders that have no command behind them at all — the 548 KB `list-commands`
|
|
14
|
+
* manifest, a login summary, a logout status.
|
|
15
|
+
*
|
|
16
|
+
* 2026-07-23: the banner used to call `--output-path` a "universal remedy
|
|
17
|
+
* (works on every command)". It is not. Plain-JSON commands REFUSE the flag,
|
|
18
|
+
* and the two commands that trip the banner most often (`search-all-files`,
|
|
19
|
+
* `microsoft-search-query`) advertise only `--query` — so every remedy the
|
|
20
|
+
* banner named was a dead end there, and an agentic caller following it burned
|
|
21
|
+
* a call to find out.
|
|
22
|
+
*/
|
|
23
|
+
type SizeHintContext = {
|
|
24
|
+
readonly commandName: string;
|
|
25
|
+
/** `meta.producesBytes` — the manifest flag that decides whether --output-path is accepted. */
|
|
26
|
+
readonly producesBytes: boolean;
|
|
27
|
+
readonly supportsSelect: boolean;
|
|
28
|
+
readonly supportsTop: boolean;
|
|
29
|
+
readonly surface: RenderSurface;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Render a use-case success value to its final string, newline included.
|
|
33
|
+
* `output.ts` writes this to stdout; `mcp.ts` returns it as tool content.
|
|
34
|
+
*
|
|
35
|
+
* `context` is what makes the oversized-response banner honest — pass it
|
|
36
|
+
* whenever a registry command produced the data. Omit it for the renders that
|
|
37
|
+
* have no command behind them; the banner then claims no flag-level remedy.
|
|
38
|
+
*/
|
|
39
|
+
declare const renderToString: (data: unknown, format: OutputFormat, context?: SizeHintContext) => string;
|
|
40
|
+
/**
|
|
41
|
+
* Render an error to its final string, newline included. The `hint` / `source`
|
|
42
|
+
* lookup is shared with the CLI so an MCP consumer sees the same curated
|
|
43
|
+
* remedies (`error-hints.ts`) the terminal does.
|
|
44
|
+
*/
|
|
45
|
+
declare const renderErrorToString: (message: string, format: OutputFormat, errorCode?: string, explicitSource?: ErrorSource, retryAfterSeconds?: number) => string;
|
|
46
|
+
export { renderErrorToString, renderToString };
|
|
47
|
+
export type { OutputFormat, RenderSurface, SizeHintContext };
|
|
@@ -14,9 +14,26 @@ import { type ODataKey } from './odata-query.js';
|
|
|
14
14
|
type SelectDefaults = {
|
|
15
15
|
readonly defaultSelect?: string;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* `defaultTop`, when set and the user did NOT pass `--top`, injects a `$top`
|
|
19
|
+
* into the OData query string. Its purpose is NOT payload-slimming (that is
|
|
20
|
+
* `defaultSelect`) but cursor correctness: a handful of `$skip`-offset-paged
|
|
21
|
+
* Graph endpoints (`/me/people` is the canonical one) only emit a
|
|
22
|
+
* self-advancing `@odata.nextLink` when `$top` is present. Without it Graph
|
|
23
|
+
* echoes back the SAME `$skip` on every page (`?$skip=0` → `?$skip=0` → …), so
|
|
24
|
+
* following the cursor loops forever on page 1. Forcing a default `$top` makes
|
|
25
|
+
* Graph increment `$skip` by the page size. Only meaningful on list builders
|
|
26
|
+
* whose OData shape carries `top`. User-supplied `--top` always wins.
|
|
27
|
+
*/
|
|
28
|
+
type ListDefaults = SelectDefaults & {
|
|
29
|
+
readonly defaultTop?: string;
|
|
30
|
+
};
|
|
31
|
+
declare const withDefaultSelect: <T extends {
|
|
32
|
+
readonly select?: string;
|
|
33
|
+
}>(data: T, defaultSelect: string | undefined) => T;
|
|
17
34
|
declare const buildCommand: (pathFn: (params: Record<string, string>) => string, schema: z.ZodType) => Pick<Command, "schema" | "execute">;
|
|
18
35
|
declare const buildElevatedCommand: (pathFn: (params: Record<string, string>) => string, schema: z.ZodType) => Pick<Command, "schema" | "execute">;
|
|
19
|
-
declare const buildListCommand: <Shape extends z.ZodRawShape>(pathFn: (params: z.infer<z.ZodObject<Shape>>) => string, schema: z.ZodObject<Shape>, options?:
|
|
36
|
+
declare const buildListCommand: <Shape extends z.ZodRawShape>(pathFn: (params: z.infer<z.ZodObject<Shape>>) => string, schema: z.ZodObject<Shape>, options?: ListDefaults) => Pick<Command, "schema" | "execute">;
|
|
20
37
|
declare const buildElevatedListCommand: <Shape extends z.ZodRawShape>(pathFn: (params: z.infer<z.ZodObject<Shape>>) => string, schema: z.ZodObject<Shape>, options?: SelectDefaults) => Pick<Command, "schema" | "execute">;
|
|
21
38
|
/**
|
|
22
39
|
* Single-resource GET that supports the OData `$select` and `$expand` query
|
|
@@ -67,4 +84,4 @@ declare const buildPickODataListCommand: <Shape extends z.ZodRawShape, K extends
|
|
|
67
84
|
* `$orderby` / `$expand` with `BadRequest`, so the picker is the right tool.
|
|
68
85
|
*/
|
|
69
86
|
declare const buildElevatedPickODataListCommand: <Shape extends z.ZodRawShape, K extends ODataKey>(pathFn: (params: z.infer<z.ZodObject<Shape>>) => string, schema: z.ZodObject<Shape>, keys: ReadonlyArray<K>, options?: SelectDefaults) => Pick<Command, "schema" | "execute">;
|
|
70
|
-
export { buildCommand, buildElevatedCommand, buildElevatedListCommand, buildElevatedPickODataListCommand, buildElevatedSelectableCommand, buildFilterSelectListCommand, buildListCommand, buildNoSkipListCommand, buildPickODataListCommand, buildSelectableCommand, };
|
|
87
|
+
export { buildCommand, buildElevatedCommand, buildElevatedListCommand, buildElevatedPickODataListCommand, buildElevatedSelectableCommand, buildFilterSelectListCommand, buildListCommand, buildNoSkipListCommand, buildPickODataListCommand, buildSelectableCommand, withDefaultSelect, };
|
|
@@ -5,10 +5,6 @@ type CommandSchema = z.ZodType;
|
|
|
5
5
|
type CommandExecute = (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, import('../../infra/graph-client.js').GraphError>>;
|
|
6
6
|
type CommandCategory = 'drive' | 'excel' | 'sharepoint' | 'tasks' | 'mail' | 'notes' | 'user' | 'calendar' | 'chats' | 'teams' | 'meta' | 'lifecycle';
|
|
7
7
|
type CommandHttpMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE';
|
|
8
|
-
type CommandOptionAlias = {
|
|
9
|
-
readonly name: string;
|
|
10
|
-
readonly key: string;
|
|
11
|
-
};
|
|
12
8
|
/**
|
|
13
9
|
* Structured type-hint for a CLI flag value. Surfaces in `help-json` so an
|
|
14
10
|
* LLM can avoid the trial-and-error of "is this an ID or a name?" prose
|
|
@@ -38,13 +34,6 @@ type CommandOptionMeta = {
|
|
|
38
34
|
* commands accept but do not demand.
|
|
39
35
|
*/
|
|
40
36
|
readonly required: boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Optional secondary spellings of the same flag. Both the canonical
|
|
43
|
-
* `name` and every alias name are accepted on the command line; values
|
|
44
|
-
* passed under an alias are normalized to the canonical `key` before
|
|
45
|
-
* the schema runs. The canonical name is what `--help` shows first.
|
|
46
|
-
*/
|
|
47
|
-
readonly aliases?: ReadonlyArray<CommandOptionAlias>;
|
|
48
37
|
/**
|
|
49
38
|
* Structured value-type hint for LLM consumers. Optional.
|
|
50
39
|
*/
|
|
@@ -80,14 +69,6 @@ type PaginationStrategy =
|
|
|
80
69
|
type CommandMeta = {
|
|
81
70
|
readonly summary: string;
|
|
82
71
|
readonly category: CommandCategory;
|
|
83
|
-
/**
|
|
84
|
-
* Deprecated former command names kept working as commander-level aliases for
|
|
85
|
-
* back-compat after a rename (e.g. `download-onedrive-file-content` →
|
|
86
|
-
* `download-drive-item-content`). The canonical registry key is what `--help`
|
|
87
|
-
* and the manifest list first; each alias here is also accepted on the CLI and
|
|
88
|
-
* surfaced in the manifest so an LLM that learned the old name still resolves.
|
|
89
|
-
*/
|
|
90
|
-
readonly commandAliases?: ReadonlyArray<string>;
|
|
91
72
|
readonly graphMethod: CommandHttpMethod;
|
|
92
73
|
readonly graphPathTemplate: string;
|
|
93
74
|
readonly graphDocsUrl: string;
|
|
@@ -109,20 +90,25 @@ type CommandMeta = {
|
|
|
109
90
|
readonly scopesRequired?: ReadonlyArray<string>;
|
|
110
91
|
/**
|
|
111
92
|
* `true` if the command needs the M365ChatClient elevated token (captured
|
|
112
|
-
* at login from `m365.cloud.microsoft`, ODSP allow-list).
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
93
|
+
* at login from `m365.cloud.microsoft`, ODSP allow-list). The exact set is
|
|
94
|
+
* pinned in meta.test.ts, and the composition root derives the auth
|
|
95
|
+
* fail-fast message's command list from this flag — a new elevated command
|
|
96
|
+
* MUST carry it or the remedy message will omit the command. An LLM should
|
|
97
|
+
* check this field before invoking; if the elevated capture failed at
|
|
98
|
+
* login, these commands fail fast with `secondary_token_unavailable`.
|
|
116
99
|
*/
|
|
117
100
|
readonly needsElevatedToken?: true;
|
|
118
101
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
102
|
+
* Which Teams substrate token the command needs: `'chatsvcagg'`
|
|
103
|
+
* (teams.microsoft.com/api/csa) or `'ic3'` (chat history), both captured
|
|
104
|
+
* at login from `teams.microsoft.com`. Truthy = "needs a substrate token"
|
|
105
|
+
* (the historical boolean semantics); the service value additionally
|
|
106
|
+
* routes the command into the right auth fail-fast list, derived by the
|
|
107
|
+
* composition root. Like `needsElevatedToken`, an LLM should check this
|
|
108
|
+
* before invoking and warm up an interactive `login`; a headless or stale
|
|
109
|
+
* session times out on these (the non-interactive silent-SSO limitation).
|
|
124
110
|
*/
|
|
125
|
-
readonly needsSubstrateToken?:
|
|
111
|
+
readonly needsSubstrateToken?: 'chatsvcagg' | 'ic3';
|
|
126
112
|
/**
|
|
127
113
|
* `true` if the command returns inlined bytes (`{contentType, size, base64}`
|
|
128
114
|
* or `{contentType, size, text}`) and is therefore a valid target for the
|
|
@@ -167,10 +153,10 @@ type Command = {
|
|
|
167
153
|
readonly meta: CommandMeta;
|
|
168
154
|
/**
|
|
169
155
|
* Present on the rare command whose input is the LOCAL filesystem instead of
|
|
170
|
-
* Graph (`convert-local-file`). The CLI routes execution here, passing its
|
|
156
|
+
* Graph (`convert-local-file-to-markdown`). The CLI routes execution here, passing its
|
|
171
157
|
* composition-selected FileSystem; `execute` stays as the registry-typed
|
|
172
158
|
* fallback that redirects library consumers to this variant.
|
|
173
159
|
*/
|
|
174
160
|
readonly executeLocal?: (fs: import('../ports/filesystem.js').FileSystem, params: Record<string, string>) => Promise<Result<unknown, import('../../infra/graph-client.js').GraphError>>;
|
|
175
161
|
};
|
|
176
|
-
export type { ArgumentHint, Command, CommandCategory, CommandExecute, CommandHttpMethod, CommandMeta,
|
|
162
|
+
export type { ArgumentHint, Command, CommandCategory, CommandExecute, CommandHttpMethod, CommandMeta, CommandOptionMeta, CommandPositionalArgumentMeta, CommandSchema, PaginationStrategy, };
|
|
@@ -9,6 +9,10 @@ declare const schema: z.ZodObject<{
|
|
|
9
9
|
true: "true";
|
|
10
10
|
false: "false";
|
|
11
11
|
}>>;
|
|
12
|
+
keepQuoted: z.ZodOptional<z.ZodEnum<{
|
|
13
|
+
true: "true";
|
|
14
|
+
false: "false";
|
|
15
|
+
}>>;
|
|
12
16
|
}, z.core.$strip>;
|
|
13
17
|
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
14
18
|
declare const meta: CommandMeta;
|
|
@@ -14,12 +14,17 @@ import type { CommandMeta } from './command-types.js';
|
|
|
14
14
|
* rather than failing the whole archive.
|
|
15
15
|
*/
|
|
16
16
|
declare const schema: z.ZodObject<{
|
|
17
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
17
18
|
driveId: z.ZodString;
|
|
18
19
|
itemId: z.ZodString;
|
|
19
20
|
includeMetadata: z.ZodOptional<z.ZodEnum<{
|
|
20
21
|
true: "true";
|
|
21
22
|
false: "false";
|
|
22
23
|
}>>;
|
|
24
|
+
keepQuoted: z.ZodOptional<z.ZodEnum<{
|
|
25
|
+
true: "true";
|
|
26
|
+
false: "false";
|
|
27
|
+
}>>;
|
|
23
28
|
}, z.core.$strip>;
|
|
24
29
|
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
25
30
|
declare const meta: CommandMeta;
|
|
@@ -9,9 +9,17 @@ declare const schema: z.ZodObject<{
|
|
|
9
9
|
true: "true";
|
|
10
10
|
false: "false";
|
|
11
11
|
}>>;
|
|
12
|
+
keepQuoted: z.ZodOptional<z.ZodEnum<{
|
|
13
|
+
true: "true";
|
|
14
|
+
false: "false";
|
|
15
|
+
}>>;
|
|
12
16
|
}, z.core.$strip>;
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
type ConvertOptions = {
|
|
18
|
+
readonly includeMetadata: boolean;
|
|
19
|
+
readonly keepQuoted: boolean;
|
|
20
|
+
};
|
|
21
|
+
declare const convertFetchedAttachment: (graph: GraphClient, a: Record<string, unknown>, opts: ConvertOptions) => Promise<Result<unknown, GraphError>> | Result<unknown, GraphError>;
|
|
22
|
+
declare const convertAttachmentToMarkdown: (graph: GraphClient, attachmentPath: string, opts: ConvertOptions) => Promise<Result<unknown, GraphError>>;
|
|
15
23
|
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
16
24
|
declare const meta: CommandMeta;
|
|
17
25
|
export { convertAttachmentToMarkdown, convertFetchedAttachment, execute, meta, schema };
|
|
@@ -4,7 +4,7 @@ import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
|
4
4
|
import type { CommandMeta } from './command-types.js';
|
|
5
5
|
/**
|
|
6
6
|
* Unzips a `.zip` Outlook mail attachment and converts every contained file in one
|
|
7
|
-
* call — the mail-side mirror of `convert-drive-item-zip`. Without it, reading a
|
|
7
|
+
* call — the mail-side mirror of `convert-drive-item-zip-to-markdown`. Without it, reading a
|
|
8
8
|
* zipped vendor deck meant: `get-mail-attachment --output-path x.zip` → manual
|
|
9
9
|
* `unzip` (with `-O GBK` for Chinese names) → convert each file. This collapses all
|
|
10
10
|
* of that into one command: it pulls the fileAttachment bytes, unzips them (legacy
|
|
@@ -18,6 +18,10 @@ declare const schema: z.ZodObject<{
|
|
|
18
18
|
true: "true";
|
|
19
19
|
false: "false";
|
|
20
20
|
}>>;
|
|
21
|
+
keepQuoted: z.ZodOptional<z.ZodEnum<{
|
|
22
|
+
true: "true";
|
|
23
|
+
false: "false";
|
|
24
|
+
}>>;
|
|
21
25
|
}, z.core.$strip>;
|
|
22
26
|
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
23
27
|
declare const meta: CommandMeta;
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import type { Result } from '../../domain/result.js';
|
|
3
3
|
import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
4
4
|
import type { CommandMeta } from './command-types.js';
|
|
5
|
+
import { type InlineAttachment } from './inline-image-embedder.js';
|
|
5
6
|
declare const schema: z.ZodObject<{
|
|
6
7
|
messageId: z.ZodString;
|
|
7
8
|
inlineImages: z.ZodOptional<z.ZodEnum<{
|
|
@@ -13,6 +14,39 @@ declare const schema: z.ZodObject<{
|
|
|
13
14
|
false: "false";
|
|
14
15
|
}>>;
|
|
15
16
|
}, z.core.$strip>;
|
|
17
|
+
declare const ATTACHMENT_METADATA_SELECT = "$select=id,name,contentType,size,isInline,microsoft.graph.fileAttachment/contentId";
|
|
18
|
+
declare const attachmentMetaSchema: z.ZodObject<{
|
|
19
|
+
id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
|
+
name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
|
+
contentType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
22
|
+
size: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
23
|
+
isInline: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
24
|
+
contentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
declare const attachmentsListSchema: z.ZodObject<{
|
|
27
|
+
value: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
28
|
+
id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
29
|
+
name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
30
|
+
contentType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
31
|
+
size: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
32
|
+
isInline: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
33
|
+
contentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
34
|
+
}, z.core.$strip>>>;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
type AttachmentMeta = z.infer<typeof attachmentMetaSchema>;
|
|
37
|
+
declare const formatBytes: (n: number) => string;
|
|
38
|
+
type InlineImageCandidate = AttachmentMeta & {
|
|
39
|
+
readonly contentType: string;
|
|
40
|
+
readonly contentId: string;
|
|
41
|
+
};
|
|
42
|
+
declare const isInlineImage: (a: AttachmentMeta) => a is InlineImageCandidate;
|
|
43
|
+
type EmbedFetchResult = {
|
|
44
|
+
readonly meta: InlineImageCandidate;
|
|
45
|
+
readonly inline?: InlineAttachment;
|
|
46
|
+
readonly oversize: boolean;
|
|
47
|
+
};
|
|
48
|
+
declare const fetchInlineImageBytes: (graph: GraphClient, messageId: string, meta: InlineImageCandidate) => Promise<EmbedFetchResult>;
|
|
16
49
|
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
17
50
|
declare const meta: CommandMeta;
|
|
18
|
-
export { execute, meta, schema };
|
|
51
|
+
export { ATTACHMENT_METADATA_SELECT, attachmentsListSchema, execute, fetchInlineImageBytes, formatBytes, isInlineImage, meta, schema };
|
|
52
|
+
export type { AttachmentMeta, InlineImageCandidate };
|
|
@@ -4,8 +4,12 @@ declare const schema: z.ZodObject<{
|
|
|
4
4
|
forwardMessageId: z.ZodString;
|
|
5
5
|
toRecipients: z.ZodString;
|
|
6
6
|
ccRecipients: z.ZodOptional<z.ZodString>;
|
|
7
|
-
|
|
7
|
+
comment: z.ZodString;
|
|
8
8
|
subject: z.ZodOptional<z.ZodString>;
|
|
9
|
+
bodyContentType: z.ZodOptional<z.ZodEnum<{
|
|
10
|
+
Text: "Text";
|
|
11
|
+
HTML: "HTML";
|
|
12
|
+
}>>;
|
|
9
13
|
}, z.core.$strip>;
|
|
10
14
|
declare const execute: Command['execute'];
|
|
11
15
|
declare const meta: CommandMeta;
|
|
@@ -2,8 +2,16 @@ import { z } from 'zod';
|
|
|
2
2
|
import type { Command, CommandMeta } from './command-types.js';
|
|
3
3
|
declare const schema: z.ZodObject<{
|
|
4
4
|
replyToMessageId: z.ZodString;
|
|
5
|
-
|
|
5
|
+
comment: z.ZodString;
|
|
6
6
|
subject: z.ZodOptional<z.ZodString>;
|
|
7
|
+
replyAll: z.ZodOptional<z.ZodEnum<{
|
|
8
|
+
true: "true";
|
|
9
|
+
false: "false";
|
|
10
|
+
}>>;
|
|
11
|
+
bodyContentType: z.ZodOptional<z.ZodEnum<{
|
|
12
|
+
Text: "Text";
|
|
13
|
+
HTML: "HTML";
|
|
14
|
+
}>>;
|
|
7
15
|
}, z.core.$strip>;
|
|
8
16
|
declare const execute: Command['execute'];
|
|
9
17
|
declare const meta: CommandMeta;
|
|
@@ -3,7 +3,6 @@ export type CommandManifestEntry = {
|
|
|
3
3
|
readonly name: string;
|
|
4
4
|
readonly summary: string;
|
|
5
5
|
readonly category: CommandCategory;
|
|
6
|
-
readonly commandAliases?: CommandMeta['commandAliases'];
|
|
7
6
|
readonly graphMethod: CommandMeta['graphMethod'];
|
|
8
7
|
readonly graphPathTemplate: string;
|
|
9
8
|
readonly graphDocsUrl: string;
|
|
@@ -3,8 +3,6 @@ import type { Result } from '../../domain/result.js';
|
|
|
3
3
|
import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
4
4
|
import type { CommandMeta } from './command-types.js';
|
|
5
5
|
declare const schema: z.ZodObject<{
|
|
6
|
-
driveId: z.ZodString;
|
|
7
|
-
itemId: z.ZodString;
|
|
8
6
|
includeMetadata: z.ZodOptional<z.ZodEnum<{
|
|
9
7
|
true: "true";
|
|
10
8
|
false: "false";
|
|
@@ -13,7 +11,14 @@ declare const schema: z.ZodObject<{
|
|
|
13
11
|
true: "true";
|
|
14
12
|
false: "false";
|
|
15
13
|
}>>;
|
|
14
|
+
keepQuoted: z.ZodOptional<z.ZodEnum<{
|
|
15
|
+
true: "true";
|
|
16
|
+
false: "false";
|
|
17
|
+
}>>;
|
|
16
18
|
maxCells: z.ZodOptional<z.ZodString>;
|
|
19
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
20
|
+
driveId: z.ZodString;
|
|
21
|
+
itemId: z.ZodString;
|
|
17
22
|
}, z.core.$strip>;
|
|
18
23
|
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
19
24
|
declare const meta: CommandMeta;
|
|
@@ -3,6 +3,7 @@ import type { Result } from '../../domain/result.js';
|
|
|
3
3
|
import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
4
4
|
import type { CommandMeta } from './command-types.js';
|
|
5
5
|
declare const schema: z.ZodObject<{
|
|
6
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
6
7
|
driveId: z.ZodString;
|
|
7
8
|
itemId: z.ZodString;
|
|
8
9
|
}, z.core.$strip>;
|
|
@@ -3,6 +3,7 @@ import type { Result } from '../../domain/result.js';
|
|
|
3
3
|
import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
4
4
|
import type { CommandMeta } from './command-types.js';
|
|
5
5
|
declare const schema: z.ZodObject<{
|
|
6
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
6
7
|
driveId: z.ZodString;
|
|
7
8
|
itemId: z.ZodString;
|
|
8
9
|
}, z.core.$strip>;
|