ask-marcel-office-cli 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +201 -0
- package/README.md +45 -26
- package/dist/cli.js +2964 -2446
- package/dist/commands.json +254 -727
- package/dist/composition/run-registry-command.d.ts +12 -3
- package/dist/domain/utilities/base64.d.ts +11 -0
- package/dist/index.js +2121 -1737
- package/dist/infra/auth.d.ts +30 -4
- package/dist/infra/browser-auth.d.ts +21 -1
- package/dist/presenter/output-text.d.ts +1 -1
- package/dist/presenter/output.d.ts +2 -2
- package/dist/presenter/render-to-string.d.ts +42 -2
- package/dist/use-cases/commands/command-types.d.ts +1 -20
- package/dist/use-cases/commands/create-forward-draft.d.ts +1 -1
- package/dist/use-cases/commands/create-reply-draft.d.ts +1 -1
- package/dist/use-cases/commands/docs-render.d.ts +0 -1
- package/dist/use-cases/commands/docx-metadata.d.ts +32 -2
- package/dist/use-cases/commands/draft-comment-splicer.d.ts +8 -1
- package/dist/use-cases/commands/include-hidden-folders.d.ts +2 -0
- package/dist/use-cases/commands/list-mail-folder-messages-delta.d.ts +10 -2
- package/dist/use-cases/commands/list-shared-mailbox-child-folders.d.ts +4 -0
- package/dist/use-cases/commands/list-shared-mailbox-folders.d.ts +4 -0
- package/dist/use-cases/commands/login-status.d.ts +2 -0
- package/dist/use-cases/commands/login.d.ts +18 -8
- package/dist/use-cases/commands/next-page.d.ts +1 -0
- package/dist/use-cases/commands/ooxml-xml-walker.d.ts +31 -6
- package/dist/use-cases/commands/pptx-comments.d.ts +8 -5
- package/dist/use-cases/commands/reject-unknown-params.d.ts +16 -0
- package/dist/use-cases/commands/resolve-command.d.ts +7 -9
- package/dist/use-cases/commands/search-onenote-pages.d.ts +1 -1
- package/dist/use-cases/commands/token-tier-capability.d.ts +5 -0
- package/dist/use-cases/commands/update-mail-draft.d.ts +4 -0
- package/docs/COMMANDS.md +15 -13
- package/docs/USAGE.md +2 -2
- package/package.json +25 -9
package/dist/infra/auth.d.ts
CHANGED
|
@@ -39,7 +39,9 @@ type AuthManager = {
|
|
|
39
39
|
* `logicalPermissions` allow-list. Falls through cache → re-capture
|
|
40
40
|
* via headless Playwright. Used by the 3 historical-version commands.
|
|
41
41
|
*/
|
|
42
|
-
getElevatedAccessToken: (
|
|
42
|
+
getElevatedAccessToken: (options?: {
|
|
43
|
+
readonly awaitSignIn?: boolean;
|
|
44
|
+
}) => Promise<Result<AccessToken, AuthError>>;
|
|
43
45
|
/**
|
|
44
46
|
* Returns a Graph token issued by a PARTNER tenant's authority, for a user
|
|
45
47
|
* who is a guest there. Without it, every call against that tenant's
|
|
@@ -54,7 +56,9 @@ type AuthManager = {
|
|
|
54
56
|
* through cache → re-capture via headless Playwright. Used by the
|
|
55
57
|
* `list-teams-chats-with-messages` family of commands.
|
|
56
58
|
*/
|
|
57
|
-
getChatsvcaggAccessToken: (
|
|
59
|
+
getChatsvcaggAccessToken: (options?: {
|
|
60
|
+
readonly ignoreCache?: boolean;
|
|
61
|
+
}) => Promise<Result<AccessToken, AuthError>>;
|
|
58
62
|
/**
|
|
59
63
|
* Returns the regional segment used to construct chatsvcagg substrate
|
|
60
64
|
* URLs (`teams.microsoft.com/api/csa/<region>/api/...`). Captured at
|
|
@@ -71,7 +75,17 @@ type AuthManager = {
|
|
|
71
75
|
* via headless Playwright. Used by `list-teams-chat-history` to walk
|
|
72
76
|
* paginated chat-message history beyond the 200-message chatsvcagg cap.
|
|
73
77
|
*/
|
|
74
|
-
getIc3AccessToken: (
|
|
78
|
+
getIc3AccessToken: (options?: {
|
|
79
|
+
readonly ignoreCache?: boolean;
|
|
80
|
+
}) => Promise<Result<AccessToken, AuthError>>;
|
|
81
|
+
/**
|
|
82
|
+
* Redeem the shared refresh token for any COLD substrate tier, over HTTP, with
|
|
83
|
+
* no browser on any path. `login` calls this so a warm-cache sign-in leaves all
|
|
84
|
+
* four tiers usable; without it the two substrate tiers stay cold until some
|
|
85
|
+
* Teams-chat command pays for them, and `login` reports them missing while
|
|
86
|
+
* having done nothing about it.
|
|
87
|
+
*/
|
|
88
|
+
warmSubstrateTokens?: () => Promise<void>;
|
|
75
89
|
logout: () => Promise<Result<void, AuthError>>;
|
|
76
90
|
/**
|
|
77
91
|
* Inspect the elevated-capture outcome from the most recent
|
|
@@ -95,6 +109,16 @@ type AuthManager = {
|
|
|
95
109
|
* Optional: only the real manager implements it; a minimal fake omits it
|
|
96
110
|
* and callers treat that as unavailable. Never captures or refreshes.
|
|
97
111
|
*/
|
|
112
|
+
/**
|
|
113
|
+
* The cached BASIC token, decoded by `scopes-check` and never acquired: no
|
|
114
|
+
* refresh, no browser. The acquiring getter heals a dead session by opening
|
|
115
|
+
* a browser and, when the persistent profile is already signed in, wiping it
|
|
116
|
+
* so the grant re-fires (2026-09-02: a diagnostic did exactly that). A stale
|
|
117
|
+
* token comes back as-is so its expiry can be reported; no cache at all is
|
|
118
|
+
* `undefined`. Optional: a bring-your-own-token manager omits it and callers
|
|
119
|
+
* fall back to `getAccessToken`, which is then the caller's own function.
|
|
120
|
+
*/
|
|
121
|
+
getCachedBasicToken?: () => Promise<AccessToken | undefined>;
|
|
98
122
|
getCachedElevatedInfo?: () => Promise<CachedTierInfo>;
|
|
99
123
|
/**
|
|
100
124
|
* Same decode-only preflight as `getCachedElevatedInfo`, for the chatsvcagg /
|
|
@@ -120,7 +144,8 @@ type SecondaryTokenCommands = {
|
|
|
120
144
|
readonly chatsvcagg: ReadonlyArray<string>;
|
|
121
145
|
readonly ic3: ReadonlyArray<string>;
|
|
122
146
|
};
|
|
123
|
-
|
|
147
|
+
type FetchFn = (url: string, init?: RequestInit) => Promise<Response>;
|
|
148
|
+
declare const createAuthManagerFromApi: (browserAuth: BrowserAuth, cachePath: string, browserProfileDir: string, logger: Logger, fs: FileSystem, recaptureSecondaryViaBrowser?: boolean, secondaryTokenCommands?: SecondaryTokenCommands, acquireBasicViaBrowser?: boolean, recaptureElevatedViaBrowser?: boolean, fetchFn?: FetchFn) => AuthManager;
|
|
124
149
|
/**
|
|
125
150
|
* Probe the token cache for a fresh access token. Handed to the browser
|
|
126
151
|
* capture so its poll loop can short-circuit the multi-minute dance
|
|
@@ -138,6 +163,7 @@ declare const createAuthManager: (deps: {
|
|
|
138
163
|
recaptureSecondaryViaBrowser?: boolean;
|
|
139
164
|
secondaryTokenCommands?: SecondaryTokenCommands;
|
|
140
165
|
acquireBasicViaBrowser?: boolean;
|
|
166
|
+
recaptureElevatedViaBrowser?: boolean;
|
|
141
167
|
}) => AuthManager;
|
|
142
168
|
export { createAuthManager, createAuthManagerFromApi, createFreshCachedTokenProbe, stderrProgress };
|
|
143
169
|
export type { AuthError, AuthManager, CachedTierInfo, ElevatedOutcome, SecondaryTokenCommands };
|
|
@@ -115,8 +115,16 @@ type BrowserAuth = {
|
|
|
115
115
|
* cached elevated token expires and the Teams session is already in
|
|
116
116
|
* the cache (no fresh sign-in needed). On `login`, use
|
|
117
117
|
* `acquireBothTokens` instead so the user sees only one browser.
|
|
118
|
+
*
|
|
119
|
+
* `awaitSignIn` says a human asked for this and is watching, so the capture
|
|
120
|
+
* gets the interactive `pollDeadlineMs` rather than the short silent cap:
|
|
121
|
+
* long enough for a slow redirect chain, and long enough to fill in a
|
|
122
|
+
* sign-in form if one appears. Without it the short cap applies and the
|
|
123
|
+
* capture fails fast, which is what a background command needs.
|
|
118
124
|
*/
|
|
119
|
-
acquireElevatedToken: (
|
|
125
|
+
acquireElevatedToken: (options?: {
|
|
126
|
+
readonly awaitSignIn?: boolean;
|
|
127
|
+
}) => Promise<ElevatedTokenResult>;
|
|
120
128
|
/**
|
|
121
129
|
* Capture a chatsvcagg-audience bearer (Teams basic identity, but the
|
|
122
130
|
* `chatsvcagg.teams.microsoft.com` resource instead of Graph) by
|
|
@@ -223,6 +231,12 @@ type BrowserAuthConfig = {
|
|
|
223
231
|
readonly initialSettleMs?: number;
|
|
224
232
|
readonly postReloginSettleMs?: number;
|
|
225
233
|
readonly pollIntervalMs?: number;
|
|
234
|
+
/**
|
|
235
|
+
* How long to keep listening for the PREFERRED elevated identity after an
|
|
236
|
+
* acceptable-but-weaker one has already been captured. See
|
|
237
|
+
* `PREFERRED_ELEVATED_APP_ID`.
|
|
238
|
+
*/
|
|
239
|
+
readonly elevatedPreferenceGraceMs?: number;
|
|
226
240
|
readonly pollDeadlineMs?: number;
|
|
227
241
|
readonly navigationTimeoutMs?: number;
|
|
228
242
|
/**
|
|
@@ -234,6 +248,12 @@ type BrowserAuthConfig = {
|
|
|
234
248
|
* the LLM tool-call window. With a tight cap, the flow either yields
|
|
235
249
|
* a token quickly or fails with `auth_failed: elevated token capture
|
|
236
250
|
* timed out — run `ask-marcel-office login` to refresh.`
|
|
251
|
+
*
|
|
252
|
+
* The cap applies only when nobody is waiting. A caller passing
|
|
253
|
+
* `awaitSignIn` (today just `login`) gets `pollDeadlineMs` instead, because
|
|
254
|
+
* a silent capture that merely runs SLOW would otherwise fail here and send
|
|
255
|
+
* `login` into the forced dance, whose cookie wipe costs the 90-day sign-in
|
|
256
|
+
* session and guarantees the next run prompts.
|
|
237
257
|
*/
|
|
238
258
|
readonly elevatedRecaptureTimeoutMs?: number;
|
|
239
259
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const renderTextOutput: (data: unknown) => string;
|
|
1
|
+
declare const renderTextOutput: (data: unknown, tenantId?: string) => string;
|
|
2
2
|
export { renderTextOutput };
|
|
@@ -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
|
-
import type { OutputFormat } from './render-to-string.js';
|
|
4
|
-
declare const render: (data: unknown, logger: Logger, format: OutputFormat) => void;
|
|
3
|
+
import type { OutputFormat, RenderContext } from './render-to-string.js';
|
|
4
|
+
declare const render: (data: unknown, logger: Logger, format: OutputFormat, context?: RenderContext) => 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 };
|
|
@@ -1,10 +1,50 @@
|
|
|
1
1
|
import type { ErrorSource } from './error-hints.js';
|
|
2
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, and to render a follow-up command the caller can actually run. Built in
|
|
13
|
+
* composition (which owns the command manifest AND the invoked params); omitted
|
|
14
|
+
* by the renders that have no command behind them at all — the 548 KB
|
|
15
|
+
* `list-commands` manifest, a login summary, a logout status.
|
|
16
|
+
*
|
|
17
|
+
* 2026-07-23: the banner used to call `--output-path` a "universal remedy
|
|
18
|
+
* (works on every command)". It is not. Plain-JSON commands REFUSE the flag,
|
|
19
|
+
* and the two commands that trip the banner most often (`search-all-files`,
|
|
20
|
+
* `microsoft-search-query`) advertise only `--query` — so every remedy the
|
|
21
|
+
* banner named was a dead end there, and an agentic caller following it burned
|
|
22
|
+
* a call to find out.
|
|
23
|
+
*/
|
|
24
|
+
type RenderContext = {
|
|
25
|
+
readonly commandName: string;
|
|
26
|
+
/** `meta.producesBytes` — the manifest flag that decides whether --output-path is accepted. */
|
|
27
|
+
readonly producesBytes: boolean;
|
|
28
|
+
readonly supportsSelect: boolean;
|
|
29
|
+
readonly supportsTop: boolean;
|
|
30
|
+
readonly surface: RenderSurface;
|
|
31
|
+
/**
|
|
32
|
+
* The `--tenant-id` the call was made with, when it carried one. Unlike every
|
|
33
|
+
* field above it comes from the INVOCATION, not the manifest: a Graph cursor
|
|
34
|
+
* carries no tenant, so the footer is the only place the next call can learn
|
|
35
|
+
* which identity signed this page.
|
|
36
|
+
*/
|
|
37
|
+
readonly tenantId?: string;
|
|
38
|
+
};
|
|
3
39
|
/**
|
|
4
40
|
* Render a use-case success value to its final string, newline included.
|
|
5
41
|
* `output.ts` writes this to stdout; `mcp.ts` returns it as tool content.
|
|
42
|
+
*
|
|
43
|
+
* `context` is what makes the oversized-response banner honest — pass it
|
|
44
|
+
* whenever a registry command produced the data. Omit it for the renders that
|
|
45
|
+
* have no command behind them; the banner then claims no flag-level remedy.
|
|
6
46
|
*/
|
|
7
|
-
declare const renderToString: (data: unknown, format: OutputFormat) => string;
|
|
47
|
+
declare const renderToString: (data: unknown, format: OutputFormat, context?: RenderContext) => string;
|
|
8
48
|
/**
|
|
9
49
|
* Render an error to its final string, newline included. The `hint` / `source`
|
|
10
50
|
* lookup is shared with the CLI so an MCP consumer sees the same curated
|
|
@@ -12,4 +52,4 @@ declare const renderToString: (data: unknown, format: OutputFormat) => string;
|
|
|
12
52
|
*/
|
|
13
53
|
declare const renderErrorToString: (message: string, format: OutputFormat, errorCode?: string, explicitSource?: ErrorSource, retryAfterSeconds?: number) => string;
|
|
14
54
|
export { renderErrorToString, renderToString };
|
|
15
|
-
export type { OutputFormat };
|
|
55
|
+
export type { OutputFormat, RenderContext, RenderSurface };
|
|
@@ -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;
|
|
@@ -178,4 +159,4 @@ type Command = {
|
|
|
178
159
|
*/
|
|
179
160
|
readonly executeLocal?: (fs: import('../ports/filesystem.js').FileSystem, params: Record<string, string>) => Promise<Result<unknown, import('../../infra/graph-client.js').GraphError>>;
|
|
180
161
|
};
|
|
181
|
-
export type { ArgumentHint, Command, CommandCategory, CommandExecute, CommandHttpMethod, CommandMeta,
|
|
162
|
+
export type { ArgumentHint, Command, CommandCategory, CommandExecute, CommandHttpMethod, CommandMeta, CommandOptionMeta, CommandPositionalArgumentMeta, CommandSchema, PaginationStrategy, };
|
|
@@ -4,7 +4,7 @@ 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
9
|
bodyContentType: z.ZodOptional<z.ZodEnum<{
|
|
10
10
|
Text: "Text";
|
|
@@ -2,7 +2,7 @@ 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
7
|
replyAll: z.ZodOptional<z.ZodEnum<{
|
|
8
8
|
true: "true";
|
|
@@ -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;
|
|
@@ -4,7 +4,9 @@ import type { CustomProp, ExternalRel } from './ooxml-metadata.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Pulls the side-channel content out of a .docx zip — every text-bearing
|
|
6
6
|
* surface mammoth drops on the floor: core / app / custom doc properties,
|
|
7
|
-
* people registry, external hyperlinks, comments, tracked changes (
|
|
7
|
+
* people registry, external hyperlinks, comments, tracked changes (replacements,
|
|
8
|
+
* the insertions and deletions that pair with nothing, moves, and run /
|
|
9
|
+
* paragraph formatting changes),
|
|
8
10
|
* hidden text (w:vanish), text-box / shape text (w:txbxContent), header/footer
|
|
9
11
|
* body prose, field instructions (MERGEFIELD / HYPERLINK / DOCVARIABLE), bookmarks.
|
|
10
12
|
*
|
|
@@ -36,6 +38,28 @@ type TrackedChange = {
|
|
|
36
38
|
readonly date: string;
|
|
37
39
|
readonly text: string;
|
|
38
40
|
};
|
|
41
|
+
type Replacement = {
|
|
42
|
+
readonly deletionId: string;
|
|
43
|
+
readonly insertionId: string;
|
|
44
|
+
readonly author: string;
|
|
45
|
+
readonly date: string;
|
|
46
|
+
readonly before: string;
|
|
47
|
+
readonly after: string;
|
|
48
|
+
};
|
|
49
|
+
type Move = {
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly author: string;
|
|
52
|
+
readonly date: string;
|
|
53
|
+
readonly text: string;
|
|
54
|
+
readonly halves: 'both' | 'from-only' | 'to-only';
|
|
55
|
+
};
|
|
56
|
+
type FormatChange = {
|
|
57
|
+
readonly scope: 'run' | 'paragraph';
|
|
58
|
+
readonly author: string;
|
|
59
|
+
readonly date: string;
|
|
60
|
+
readonly text: string;
|
|
61
|
+
readonly properties: ReadonlyArray<string>;
|
|
62
|
+
};
|
|
39
63
|
type Field = {
|
|
40
64
|
readonly source: string;
|
|
41
65
|
readonly instruction: string;
|
|
@@ -57,6 +81,12 @@ type DocxMetadata = {
|
|
|
57
81
|
readonly comments: ReadonlyArray<Comment>;
|
|
58
82
|
readonly insertions: ReadonlyArray<TrackedChange>;
|
|
59
83
|
readonly deletions: ReadonlyArray<TrackedChange>;
|
|
84
|
+
/** A deletion and the insertion beside it, reported as the one edit they are. */
|
|
85
|
+
readonly replacements: ReadonlyArray<Replacement>;
|
|
86
|
+
/** Text moved elsewhere, joined by the range name that brackets both halves. */
|
|
87
|
+
readonly moves: ReadonlyArray<Move>;
|
|
88
|
+
/** Run or paragraph properties changed under revision marking. */
|
|
89
|
+
readonly formatChanges: ReadonlyArray<FormatChange>;
|
|
60
90
|
readonly hiddenText: ReadonlyArray<string>;
|
|
61
91
|
readonly textBoxes: ReadonlyArray<string>;
|
|
62
92
|
readonly headersFooters: ReadonlyArray<HeaderFooter>;
|
|
@@ -66,4 +96,4 @@ type DocxMetadata = {
|
|
|
66
96
|
};
|
|
67
97
|
declare const extractDocxMetadata: (bytes: Uint8Array) => Promise<Result<DocxMetadata, GraphError>>;
|
|
68
98
|
export { extractDocxMetadata };
|
|
69
|
-
export type { Bookmark, Comment, CustomProp, DocxMetadata, ExternalRel, Field, HeaderFooter, Person, TrackedChange };
|
|
99
|
+
export type { Bookmark, Comment, CustomProp, DocxMetadata, ExternalRel, Field, FormatChange, HeaderFooter, Move, Person, Replacement, TrackedChange };
|
|
@@ -21,9 +21,16 @@ declare const findBodyInsertStart: (html: string) => number;
|
|
|
21
21
|
* silently dropping the real quoted history below.
|
|
22
22
|
*/
|
|
23
23
|
declare const commentCarriesQuoteBoundary: (commentHtml: string) => boolean;
|
|
24
|
+
/**
|
|
25
|
+
* True when a draft body still carries the quoted history Graph minted with it.
|
|
26
|
+
* Dispatches on the draft's own contentType: the HTML and plain-text boundary
|
|
27
|
+
* markers are different things entirely. Used to refuse a whole-body replace
|
|
28
|
+
* that would drop the quote (2026-07-23 bug report).
|
|
29
|
+
*/
|
|
30
|
+
declare const bodyCarriesQuote: (contentType: string, content: string) => boolean;
|
|
24
31
|
/** The refusal copy for `commentCarriesQuoteBoundary`, named for the flag that carried it. */
|
|
25
32
|
declare const boundaryMarkerRefusal: (flagName: string) => string;
|
|
26
33
|
declare const insertCommentAboveQuote: (html: string, commentHtml: string) => SpliceResult;
|
|
27
34
|
declare const replaceCommentAboveQuote: (html: string, commentHtml: string) => SpliceResult;
|
|
28
35
|
declare const replacePlainTextCommentAboveQuote: (text: string, comment: string) => PlainTextSpliceResult;
|
|
29
|
-
export { boundaryMarkerRefusal, commentCarriesQuoteBoundary, escapeTextAsHtml, findBodyInsertStart, insertCommentAboveQuote, replaceCommentAboveQuote, replacePlainTextCommentAboveQuote, };
|
|
36
|
+
export { bodyCarriesQuote, boundaryMarkerRefusal, commentCarriesQuoteBoundary, escapeTextAsHtml, findBodyInsertStart, insertCommentAboveQuote, replaceCommentAboveQuote, replacePlainTextCommentAboveQuote, };
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Command, CommandMeta } from './command-types.js';
|
|
3
|
+
declare const schema: z.ZodObject<{
|
|
4
|
+
mailFolderId: z.ZodString;
|
|
5
|
+
filter: z.ZodOptional<z.ZodString>;
|
|
6
|
+
select: z.ZodOptional<z.ZodString>;
|
|
7
|
+
top: z.ZodOptional<z.ZodString>;
|
|
8
|
+
expand: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
declare const execute: Command['execute'];
|
|
3
11
|
declare const meta: CommandMeta;
|
|
4
12
|
export { execute, meta, schema };
|
|
@@ -13,15 +13,25 @@ declare const schema: z.ZodObject<{}, z.core.$strict>;
|
|
|
13
13
|
* loop with no exit: the command that needs elevated says "run login", login
|
|
14
14
|
* says "authenticated", the command fails identically, forever.
|
|
15
15
|
*
|
|
16
|
-
* When elevated is confirmed missing we
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* When elevated is confirmed missing we try `getElevatedAccessToken` FIRST. It
|
|
17
|
+
* drives a silent SSO against the persistent browser profile and leaves cookies
|
|
18
|
+
* untouched, so the tenant's 90-day ESTSAUTHPERSISTENT session survives and the
|
|
19
|
+
* user sees a window flash rather than a sign-in page. The `{ force: true }`
|
|
20
|
+
* dance calls `context.clearCookies()` to make the OAuth grant re-fire for the
|
|
21
|
+
* BASIC token, and that wipe deletes ESTSAUTHPERSISTENT — which is why routing
|
|
22
|
+
* every elevated expiry through it produced a credential prompt each time, and
|
|
23
|
+
* then destroyed the very session the prompt had just established.
|
|
21
24
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* The silent route is not always available (expired profile cookies, a failed
|
|
26
|
+
* launch, a blocked navigation), so any failure falls back to the forced dance:
|
|
27
|
+
* it can prompt, but it polls for five minutes and a human can finish it.
|
|
28
|
+
*
|
|
29
|
+
* Supersedes the 2026-07-16 decision to escalate straight to `{ force: true }`.
|
|
30
|
+
* That entry feared a hand-rolled re-capture would no-op against the browser
|
|
31
|
+
* adapter's `freshCachedToken` probe; the probe lives in `acquireBothTokens`,
|
|
32
|
+
* not in `acquireElevatedToken`, and elevated freshness is decided upstream by
|
|
33
|
+
* `freshElevatedToken`. Verified live 2026-08-30: silent capture in 17s with no
|
|
34
|
+
* prompt, and the same call failing against a profile a forced login had wiped.
|
|
25
35
|
*/
|
|
26
36
|
declare const execute: (auth: AuthManager, options?: {
|
|
27
37
|
force?: boolean;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
type XmlObject = Record<string, unknown>;
|
|
18
18
|
declare const parseXml: (xml: string | undefined) => unknown;
|
|
19
19
|
declare const findAll: (root: unknown, tagName: string) => ReadonlyArray<XmlObject>;
|
|
20
|
+
declare const findAllLocal: (root: unknown, localName: string) => ReadonlyArray<XmlObject>;
|
|
20
21
|
declare const textOf: (node: unknown) => string;
|
|
21
22
|
declare const attrOf: (node: XmlObject, name: string) => string;
|
|
22
23
|
/**
|
|
@@ -26,11 +27,35 @@ declare const attrOf: (node: XmlObject, name: string) => string;
|
|
|
26
27
|
* flattens every match into a single string for "the visible text of this run".
|
|
27
28
|
*/
|
|
28
29
|
declare const findAllTexts: (root: unknown, tagName: string) => ReadonlyArray<string>;
|
|
30
|
+
declare const collectText: (node: unknown, tagName: string) => string;
|
|
31
|
+
declare const collectTextLocal: (node: unknown, localName: string) => string;
|
|
29
32
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* down to its visible text by gathering every `<w:t>` (or `<w:delText>`) descendant.
|
|
33
|
+
* One element in the `preserveOrder` shape: its tag name, and the node itself
|
|
34
|
+
* (whose `[tag]` holds the ordered children and whose `:@` holds attributes).
|
|
33
35
|
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
type OrderedNode = {
|
|
37
|
+
readonly tag: string;
|
|
38
|
+
readonly node: XmlObject;
|
|
39
|
+
};
|
|
40
|
+
declare const parseXmlOrdered: (xml: string | undefined) => unknown;
|
|
41
|
+
/**
|
|
42
|
+
* Every sibling list in the tree, each in document order, elements only.
|
|
43
|
+
*
|
|
44
|
+
* Sibling lists rather than one flat stream: adjacency only means anything
|
|
45
|
+
* WITHIN a parent. A deletion ending one paragraph and an insertion opening the
|
|
46
|
+
* next are consecutive in a flat walk and unrelated in the document.
|
|
47
|
+
*/
|
|
48
|
+
declare const orderedSiblingGroups: (root: unknown) => ReadonlyArray<ReadonlyArray<OrderedNode>>;
|
|
49
|
+
/**
|
|
50
|
+
* Every element in true document order, pre-order (an element, then what it
|
|
51
|
+
* contains). Unlike `orderedSiblingGroups`, which reports a whole sibling level
|
|
52
|
+
* before descending, this is the order the start tags appear in the file, which
|
|
53
|
+
* is what reading flat range markers requires: `<w:moveFromRangeStart>` opens a
|
|
54
|
+
* span that a later element sits inside without being its child.
|
|
55
|
+
*/
|
|
56
|
+
declare const orderedElements: (root: unknown) => ReadonlyArray<OrderedNode>;
|
|
57
|
+
declare const orderedAttrOf: (node: XmlObject, name: string) => string;
|
|
58
|
+
/** The `collectText` of the ordered shape: flatten every `tagName` descendant to one string. */
|
|
59
|
+
declare const collectOrderedText: (node: XmlObject, tagName: string) => string;
|
|
60
|
+
export { attrOf, collectOrderedText, collectText, collectTextLocal, findAll, findAllLocal, findAllTexts, orderedAttrOf, orderedElements, orderedSiblingGroups, parseXml, parseXmlOrdered, textOf, };
|
|
61
|
+
export type { OrderedNode, XmlObject };
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { OoxmlZip } from '../../infra/ooxml-zip-adapter.js';
|
|
2
2
|
/**
|
|
3
3
|
* PowerPoint comments come in two formats: legacy (`ppt/commentAuthors.xml`
|
|
4
|
-
* authors by integer id + `ppt/comments/comment*.xml` `<
|
|
5
|
-
*
|
|
6
|
-
* `ppt/comments/*.xml` `<
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* authors by integer id + `ppt/comments/comment*.xml` `<cm authorId dt>` with a
|
|
5
|
+
* `<text>` body) and modern (`ppt/authors.xml` authors by GUID +
|
|
6
|
+
* `ppt/comments/*.xml` `<cm authorId created>` with a DrawingML `<t>` body).
|
|
7
|
+
* Elements are matched by local name, so the prefixes a writer happens to bind
|
|
8
|
+
* (`p:` / `p188:` / `a:` from PowerPoint, anything else from a third-party tool)
|
|
9
|
+
* never decide whether a comment is found. Both generations share the local name
|
|
10
|
+
* `cm`, so one pass reads them all; authors are resolved by id in either scheme.
|
|
9
11
|
*/
|
|
10
12
|
type CommentAuthor = {
|
|
11
13
|
readonly id: string;
|
|
12
14
|
readonly name: string;
|
|
13
15
|
readonly initials: string;
|
|
16
|
+
readonly email: string;
|
|
14
17
|
};
|
|
15
18
|
type PptxComment = {
|
|
16
19
|
readonly author: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Result } from '../../domain/result.js';
|
|
2
|
+
import type { GraphError } from '../../infra/graph-client.js';
|
|
3
|
+
import type { Command } from './command-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Returns the rejection for any param key the command does not declare, or
|
|
6
|
+
* `undefined` when every key is known. Exported for the registry wrapper.
|
|
7
|
+
*/
|
|
8
|
+
declare const rejectUnknownParams: (schema: Command["schema"], params: Record<string, string>) => Result<never, GraphError> | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Wraps a command so `execute` / `executeLocal` refuse unknown params before
|
|
11
|
+
* running. Applied at registry assembly, which is the single choke point every
|
|
12
|
+
* surface passes through — including a library caller that never touches
|
|
13
|
+
* composition.
|
|
14
|
+
*/
|
|
15
|
+
declare const withUnknownParamRejection: (command: Command) => Command;
|
|
16
|
+
export { rejectUnknownParams, withUnknownParamRejection };
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import type { Result } from '../../domain/result.js';
|
|
2
2
|
import type { Command } from './command-types.js';
|
|
3
3
|
/**
|
|
4
|
-
* Name -> command lookup
|
|
4
|
+
* Name -> command lookup shared by every non-commander front end.
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (`get-command-docs`, `run-command`, `run-write-command`) each need the same
|
|
10
|
-
* lookup — Rule of Three, so it lives here rather than inline.
|
|
6
|
+
* The MCP gateway's three command-taking tools (`get-command-docs`,
|
|
7
|
+
* `run-command`, `run-write-command`) each need the same lookup — Rule of
|
|
8
|
+
* Three, so it lives here rather than inline.
|
|
11
9
|
*
|
|
12
|
-
*
|
|
13
|
-
* (
|
|
14
|
-
*
|
|
10
|
+
* 2026-07-24: one name per command. Deprecated-name resolution
|
|
11
|
+
* (`meta.commandAliases`) was removed with the alias system; an old name gets
|
|
12
|
+
* the unknown-command rejection with the full list, same as any typo.
|
|
15
13
|
*/
|
|
16
14
|
export type ResolveCommandError = {
|
|
17
15
|
readonly type: 'unknown_command';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { Command, CommandMeta } from './command-types.js';
|
|
3
3
|
declare const schema: z.ZodObject<{
|
|
4
|
-
|
|
4
|
+
query: z.ZodString;
|
|
5
5
|
select: z.ZodOptional<z.ZodString>;
|
|
6
6
|
top: z.ZodOptional<z.ZodString>;
|
|
7
7
|
skip: z.ZodOptional<z.ZodString>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const TIER_CAPABILITY: Readonly<Record<string, string>>;
|
|
2
|
+
declare const OPTIONAL_TIERS: readonly ["elevated", "chatsvcagg", "ic3"];
|
|
3
|
+
type OptionalTier = (typeof OPTIONAL_TIERS)[number];
|
|
4
|
+
export { OPTIONAL_TIERS, TIER_CAPABILITY };
|
|
5
|
+
export type { OptionalTier };
|
|
@@ -5,6 +5,10 @@ declare const schema: z.ZodObject<{
|
|
|
5
5
|
subject: z.ZodOptional<z.ZodString>;
|
|
6
6
|
bodyContent: z.ZodOptional<z.ZodString>;
|
|
7
7
|
comment: z.ZodOptional<z.ZodString>;
|
|
8
|
+
replaceQuotedHistory: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
true: "true";
|
|
10
|
+
false: "false";
|
|
11
|
+
}>>;
|
|
8
12
|
bodyContentType: z.ZodOptional<z.ZodEnum<{
|
|
9
13
|
Text: "Text";
|
|
10
14
|
HTML: "HTML";
|