ask-marcel-office-cli 1.4.0 → 1.5.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 +65 -0
- package/README.md +68 -24
- package/dist/cli.js +7631 -90932
- package/dist/commands.json +1230 -70
- package/dist/composition/build-deps.d.ts +13 -0
- package/dist/composition/cli.d.ts +8 -0
- package/dist/domain/iso-datetime.d.ts +1 -1
- package/dist/domain/utilities/archive-status.d.ts +18 -0
- package/dist/domain/utilities/site-url-classifier.d.ts +15 -0
- package/dist/index.js +10421 -93852
- package/dist/infra/auth.d.ts +26 -3
- package/dist/infra/browser-auth.d.ts +25 -0
- package/dist/infra/graph-client.d.ts +3 -1
- package/dist/infra/legacy-doc-extractor.d.ts +14 -0
- package/dist/infra/msg-reader-adapter.d.ts +83 -0
- package/dist/infra/network-error.d.ts +1 -1
- package/dist/infra/ooxml-media-extractor.d.ts +27 -0
- package/dist/infra/ooxml-zip-adapter.d.ts +28 -0
- package/dist/infra/pdf-image-extractor.d.ts +18 -0
- package/dist/infra/pdf-text-extractor.d.ts +41 -0
- package/dist/infra/png-encode.d.ts +15 -0
- package/dist/infra/sheetjs-adapter.d.ts +1 -1
- package/dist/infra/system-browser-auth.d.ts +35 -0
- package/dist/infra/system-browser-loader.d.ts +3 -0
- package/dist/infra/token-callback-server.d.ts +31 -0
- package/dist/infra/zip-reader.d.ts +32 -0
- package/dist/presenter/error-hints.d.ts +2 -2
- package/dist/presenter/output.d.ts +1 -1
- package/dist/use-cases/commands/build-command.d.ts +1 -1
- package/dist/use-cases/commands/command-types.d.ts +42 -1
- package/dist/use-cases/commands/convert-calendar-event-attachment-to-markdown.d.ts +15 -0
- package/dist/use-cases/commands/convert-calendar-event-attachment-to-pdf.d.ts +11 -0
- package/dist/use-cases/commands/convert-drive-item-zip.d.ts +26 -0
- package/dist/use-cases/commands/convert-local-file.d.ts +37 -0
- package/dist/use-cases/commands/convert-mail-attachment-to-markdown.d.ts +7 -1
- package/dist/use-cases/commands/convert-mail-attachment-to-pdf.d.ts +2 -1
- package/dist/use-cases/commands/convert-mail-attachment-zip.d.ts +24 -0
- package/dist/use-cases/commands/convert-mail-to-markdown.d.ts +4 -0
- package/dist/use-cases/commands/create-mail-draft.d.ts +22 -0
- package/dist/use-cases/commands/doc-to-markdown.d.ts +14 -0
- package/dist/use-cases/commands/docs-render.d.ts +3 -0
- package/dist/use-cases/commands/docs.d.ts +1 -1
- package/dist/use-cases/commands/docx-comment-anchors.d.ts +22 -0
- package/dist/use-cases/commands/docx-metadata-to-markdown.d.ts +3 -0
- package/dist/use-cases/commands/docx-metadata.d.ts +69 -0
- package/dist/use-cases/commands/docx-to-markdown.d.ts +8 -3
- package/dist/use-cases/commands/download-drive-item-as-markdown.d.ts +9 -0
- package/dist/use-cases/commands/download-drive-item-version.d.ts +4 -0
- package/dist/use-cases/commands/extract-drive-item-images.d.ts +11 -0
- package/dist/use-cases/commands/extract-local-file-images.d.ts +21 -0
- package/dist/use-cases/commands/extract-mail-attachment-images.d.ts +11 -0
- package/dist/use-cases/commands/extract-sharepoint-links-in-documents.d.ts +33 -0
- package/dist/use-cases/commands/extract-sharepoint-links-in-mail.d.ts +1 -8
- package/dist/use-cases/commands/fetch-raw-bytes.d.ts +1 -0
- package/dist/use-cases/commands/file-counts.d.ts +7 -0
- package/dist/use-cases/commands/filter-archived-sites.d.ts +17 -0
- package/dist/use-cases/commands/first-sentence.d.ts +12 -0
- package/dist/use-cases/commands/get-excel-chart-image.d.ts +20 -0
- package/dist/use-cases/commands/get-onenote-page-as-markdown.d.ts +8 -0
- package/dist/use-cases/commands/get-todo-task.d.ts +9 -2
- package/dist/use-cases/commands/image-extraction.d.ts +10 -0
- package/dist/use-cases/commands/iso-datetime-schema.d.ts +1 -1
- package/dist/use-cases/commands/list-accessible-drives.d.ts +14 -0
- package/dist/use-cases/commands/list-calendar-event-attachments.d.ts +14 -0
- package/dist/use-cases/commands/mail-quote-stripper.d.ts +25 -0
- package/dist/use-cases/commands/markdown-dispatch.d.ts +29 -0
- package/dist/use-cases/commands/markdown-pipeline.d.ts +6 -2
- package/dist/use-cases/commands/media-files.d.ts +20 -0
- package/dist/use-cases/commands/msg-to-markdown.d.ts +28 -0
- package/dist/use-cases/commands/odf-content-to-markdown.d.ts +5 -0
- package/dist/use-cases/commands/odf-metadata-to-markdown.d.ts +3 -0
- package/dist/use-cases/commands/odf-metadata.d.ts +26 -0
- package/dist/use-cases/commands/odf-to-markdown.d.ts +17 -0
- package/dist/use-cases/commands/office-extensions.d.ts +13 -0
- package/dist/use-cases/commands/office-to-markdown.d.ts +6 -2
- package/dist/use-cases/commands/onenote-metadata.d.ts +21 -0
- package/dist/use-cases/commands/onenote-resource-embedder.d.ts +3 -0
- package/dist/use-cases/commands/ooxml-metadata-to-markdown.d.ts +16 -0
- package/dist/use-cases/commands/ooxml-metadata.d.ts +23 -0
- package/dist/use-cases/commands/ooxml-xml-walker.d.ts +36 -0
- package/dist/use-cases/commands/option-descriptions.d.ts +5 -0
- package/dist/use-cases/commands/output-path.d.ts +23 -0
- package/dist/use-cases/commands/pdf-to-markdown.d.ts +19 -0
- package/dist/use-cases/commands/pptx-comments.d.ts +24 -0
- package/dist/use-cases/commands/pptx-metadata-to-markdown.d.ts +3 -0
- package/dist/use-cases/commands/pptx-metadata.d.ts +33 -0
- package/dist/use-cases/commands/pptx-slides.d.ts +17 -0
- package/dist/use-cases/commands/pptx-to-markdown.d.ts +7 -0
- package/dist/use-cases/commands/read-mail-attachment.d.ts +15 -0
- package/dist/use-cases/commands/search-all-accessible-sites.d.ts +12 -0
- package/dist/use-cases/commands/search-index-total.d.ts +3 -0
- package/dist/use-cases/commands/search-sharepoint-sites-by-name.d.ts +3 -2
- package/dist/use-cases/commands/sharepoint-link-extractor.d.ts +17 -12
- package/dist/use-cases/commands/text-passthrough.d.ts +15 -2
- package/dist/use-cases/commands/todo-parse-uri-rewrite.d.ts +7 -0
- package/dist/use-cases/commands/update-mail-draft.d.ts +22 -0
- package/dist/use-cases/commands/xlsx-comments.d.ts +29 -0
- package/dist/use-cases/commands/xlsx-metadata-to-markdown.d.ts +3 -0
- package/dist/use-cases/commands/xlsx-metadata.d.ts +39 -0
- package/dist/use-cases/commands/xlsx-to-markdown.d.ts +9 -2
- package/dist/use-cases/commands/zip-archive-to-markdown.d.ts +30 -0
- package/dist/use-cases/ports/filesystem.d.ts +10 -0
- package/docs/COMMANDS.md +34 -18
- package/docs/USAGE.md +25 -8
- package/docs/commands.json +1230 -70
- package/package.json +14 -8
- /package/dist/use-cases/commands/{download-onedrive-file-content.d.ts → download-drive-item-content.d.ts} +0 -0
package/dist/infra/auth.d.ts
CHANGED
|
@@ -70,12 +70,35 @@ type AuthManager = {
|
|
|
70
70
|
*/
|
|
71
71
|
getLastChatsvcaggOutcome: () => ElevatedOutcome | null;
|
|
72
72
|
};
|
|
73
|
-
|
|
73
|
+
type SystemBrowserAuthFn = () => Promise<Result<{
|
|
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) => AuthManager;
|
|
85
|
+
/**
|
|
86
|
+
* QA-010: probe the token cache for a fresh access token. Handed to the
|
|
87
|
+
* browser capture so its poll loop can short-circuit the multi-minute dance
|
|
88
|
+
* when a concurrent process refreshes first (AAD rotates SPA refresh tokens,
|
|
89
|
+
* so the loser of the race cannot refresh and falls into the browser leg).
|
|
90
|
+
* Exported for the composition test; pure read, never writes.
|
|
91
|
+
*/
|
|
92
|
+
declare const createFreshCachedTokenProbe: (fs: FileSystem, cachePath: string) => (() => Promise<string | null>);
|
|
93
|
+
declare const stderrProgress: (line: string) => void;
|
|
74
94
|
declare const createAuthManager: (deps: {
|
|
75
95
|
cachePath: string;
|
|
76
96
|
logger: Logger;
|
|
77
97
|
fs?: FileSystem;
|
|
78
98
|
browserProfileDir?: string;
|
|
99
|
+
systemBrowserAuth?: SystemBrowserAuthFn;
|
|
100
|
+
usePlaywrightFallback?: boolean;
|
|
101
|
+
skipSystemBrowser?: boolean;
|
|
79
102
|
}) => AuthManager;
|
|
80
|
-
export { createAuthManager, createAuthManagerFromApi };
|
|
81
|
-
export type { AuthError, AuthManager, ElevatedOutcome };
|
|
103
|
+
export { createAuthManager, createAuthManagerFromApi, createFreshCachedTokenProbe, stderrProgress };
|
|
104
|
+
export type { AuthError, AuthManager, ElevatedOutcome, SystemBrowserAuthFn };
|
|
@@ -82,6 +82,14 @@ type BothTokensResult = {
|
|
|
82
82
|
readonly elevated: ElevatedTokenResult;
|
|
83
83
|
readonly chatsvcagg: ChatsvcaggTokenResult;
|
|
84
84
|
readonly ic3: Ic3TokenResult;
|
|
85
|
+
/**
|
|
86
|
+
* Set when the Teams poll short-circuited because `freshCachedToken`
|
|
87
|
+
* found a token written by a concurrent process (QA-010). The caller
|
|
88
|
+
* must NOT persist this result — the cache is already the source of
|
|
89
|
+
* truth, and `refreshToken` is null here (persisting would clobber the
|
|
90
|
+
* winner's rotated refresh token).
|
|
91
|
+
*/
|
|
92
|
+
readonly fromCache?: true;
|
|
85
93
|
};
|
|
86
94
|
type BrowserAuth = {
|
|
87
95
|
acquireToken: (scopes: string[], startUrl: string) => Promise<BrowserTokenResult | null>;
|
|
@@ -190,6 +198,21 @@ type BrowserAuthConfig = {
|
|
|
190
198
|
readonly logger: Logger;
|
|
191
199
|
readonly fs: FileSystem;
|
|
192
200
|
readonly trace?: TraceFn;
|
|
201
|
+
/**
|
|
202
|
+
* QA-010 (login hang): probe for a fresh token that landed in the cache
|
|
203
|
+
* WHILE the browser capture is polling. AAD SPA refresh tokens rotate, so
|
|
204
|
+
* when two processes race, the loser's refresh fails and it falls into the
|
|
205
|
+
* full multi-minute browser dance — while the winner's fresh token sits in
|
|
206
|
+
* the cache the whole time. The Teams poll loop calls this every interval
|
|
207
|
+
* and short-circuits (closing the browser) the moment it returns a token.
|
|
208
|
+
*/
|
|
209
|
+
readonly freshCachedToken?: () => Promise<string | null>;
|
|
210
|
+
/**
|
|
211
|
+
* User-visible progress sink (stderr in production). The browser capture
|
|
212
|
+
* can legitimately take minutes (federated SSO, interactive sign-in); these
|
|
213
|
+
* one-liners are what separates "waiting on the user" from "hung" (QA-010).
|
|
214
|
+
*/
|
|
215
|
+
readonly onProgress?: (line: string) => void;
|
|
193
216
|
readonly profileDir?: string;
|
|
194
217
|
readonly initialSettleMs?: number;
|
|
195
218
|
readonly postReloginSettleMs?: number;
|
|
@@ -223,6 +246,8 @@ declare const createBrowserAuthFromApi: (api: BrowserAuthApi, config: BrowserAut
|
|
|
223
246
|
declare const createBrowserAuth: (deps: {
|
|
224
247
|
logger: Logger;
|
|
225
248
|
fs?: FileSystem;
|
|
249
|
+
freshCachedToken?: () => Promise<string | null>;
|
|
250
|
+
onProgress?: (line: string) => void;
|
|
226
251
|
}) => BrowserAuth;
|
|
227
252
|
export { createBrowserAuth, createBrowserAuthFromApi, createPlaywrightApi };
|
|
228
253
|
export type { BothTokensResult, BrowserAuth, BrowserAuthApi, BrowserAuthConfig, BrowserTokenResult, ChatsvcaggTokenResult, Ic3TokenResult, ChromiumLike, ContextLike, ElevatedFailureReason, ElevatedTokenResult, PageLike, PlaywrightLoader, RequestLike, ResponseLike, };
|
|
@@ -5,6 +5,7 @@ type GraphError = {
|
|
|
5
5
|
status: number;
|
|
6
6
|
message: string;
|
|
7
7
|
code?: string;
|
|
8
|
+
retryAfterSeconds?: number;
|
|
8
9
|
} | {
|
|
9
10
|
type: 'auth_failed';
|
|
10
11
|
message: string;
|
|
@@ -66,6 +67,7 @@ type GraphClient = {
|
|
|
66
67
|
*/
|
|
67
68
|
teamsChatIc3: (path: string) => Promise<Result<unknown, GraphError>>;
|
|
68
69
|
post: (path: string, body: unknown) => Promise<Result<unknown, GraphError>>;
|
|
70
|
+
patch: (path: string, body: unknown) => Promise<Result<unknown, GraphError>>;
|
|
69
71
|
getBinary: (path: string) => Promise<Result<unknown, GraphError>>;
|
|
70
72
|
/**
|
|
71
73
|
* Same shape as `getBinary` but signs the request with an "elevated"
|
|
@@ -107,7 +109,7 @@ type TokenInfo = {
|
|
|
107
109
|
/**
|
|
108
110
|
* Seconds remaining until the cached token's `exp` claim — derived from
|
|
109
111
|
* `expiresAt - now`. Negative when the token has already expired. Absent
|
|
110
|
-
* when the JWT did not carry an `exp` claim. Audit
|
|
112
|
+
* when the JWT did not carry an `exp` claim. Audit Jane-session §4: lets
|
|
111
113
|
* an LLM decide pre-emptively to run `ask-marcel login` (re-auth typically
|
|
112
114
|
* worth doing under ~5 minutes) without parsing the ISO string itself.
|
|
113
115
|
*/
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { GraphError } from './graph-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract the text of a legacy Word .doc — the pre-2007 OLE binary "Compound
|
|
5
|
+
* File" format that mammoth (which only reads the OOXML .docx zip) cannot parse —
|
|
6
|
+
* via word-extractor (pure-JS, walks the WordDocument OLE stream; no native deps).
|
|
7
|
+
* Body text only: legacy .doc carries no structure this CLI surfaces (headings,
|
|
8
|
+
* tables, and styling are lost), so callers return it as text/plain.
|
|
9
|
+
*
|
|
10
|
+
* try/catch is permitted here per the infra-boundary rule: word-extractor throws
|
|
11
|
+
* on a non-.doc / corrupt OLE container, and we translate that into a Result.
|
|
12
|
+
*/
|
|
13
|
+
declare const extractDocText: (bytes: Uint8Array) => Promise<Result<string, GraphError>>;
|
|
14
|
+
export { extractDocText };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { GraphError } from './graph-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Parse an Outlook `.msg` file — the OLE Compound File (CFBF) container Outlook
|
|
5
|
+
* writes when you drag an email to disk, same binary family as legacy .doc/.xls —
|
|
6
|
+
* into a clean {@link ParsedMsg} via @kenjiuno/msgreader (pure-JS, no native deps,
|
|
7
|
+
* lazy-imported like word-extractor / unpdf so it stays out of the cold-start path).
|
|
8
|
+
*
|
|
9
|
+
* The adapter is the anti-corruption layer: msgreader returns a wide `FieldsData`
|
|
10
|
+
* (X500 sender addresses, RTF body, hundreds of MAPI props); {@link mapRawMsg}
|
|
11
|
+
* narrows it to the half-dozen fields the markdown renderer needs and resolves the
|
|
12
|
+
* sender SMTP / delivery-time fallbacks. `mapRawMsg` is pure and exported so every
|
|
13
|
+
* fallback branch is unit-tested with plain objects — the binary fixture only
|
|
14
|
+
* exercises one field combination.
|
|
15
|
+
*
|
|
16
|
+
* try/catch is permitted here per the infra-boundary rule: msgreader throws on a
|
|
17
|
+
* non-OLE / corrupt container, and a single unreadable attachment must not sink the
|
|
18
|
+
* whole parse, so attachment reads are individually guarded.
|
|
19
|
+
*/
|
|
20
|
+
type MsgRecipientKind = 'to' | 'cc' | 'bcc' | 'unknown';
|
|
21
|
+
type MsgRecipient = {
|
|
22
|
+
readonly kind: MsgRecipientKind;
|
|
23
|
+
readonly name?: string;
|
|
24
|
+
readonly email?: string;
|
|
25
|
+
};
|
|
26
|
+
type MsgAttachment = {
|
|
27
|
+
readonly fileName?: string;
|
|
28
|
+
readonly content?: Uint8Array;
|
|
29
|
+
};
|
|
30
|
+
type ParsedMsg = {
|
|
31
|
+
readonly subject?: string;
|
|
32
|
+
readonly senderName?: string;
|
|
33
|
+
readonly senderEmail?: string;
|
|
34
|
+
readonly date?: string;
|
|
35
|
+
readonly body?: string;
|
|
36
|
+
readonly bodyHtml?: string;
|
|
37
|
+
readonly recipients: readonly MsgRecipient[];
|
|
38
|
+
readonly attachments: readonly MsgAttachment[];
|
|
39
|
+
};
|
|
40
|
+
type RawRecipient = {
|
|
41
|
+
readonly recipType?: string;
|
|
42
|
+
readonly name?: string;
|
|
43
|
+
readonly smtpAddress?: string;
|
|
44
|
+
readonly email?: string;
|
|
45
|
+
};
|
|
46
|
+
type RawAttachment = {
|
|
47
|
+
readonly fileName?: string;
|
|
48
|
+
};
|
|
49
|
+
type RawMsg = {
|
|
50
|
+
readonly subject?: string;
|
|
51
|
+
readonly senderName?: string;
|
|
52
|
+
readonly senderSmtpAddress?: string;
|
|
53
|
+
readonly senderEmail?: string;
|
|
54
|
+
readonly messageDeliveryTime?: string;
|
|
55
|
+
readonly clientSubmitTime?: string;
|
|
56
|
+
readonly body?: string;
|
|
57
|
+
readonly bodyHtml?: string;
|
|
58
|
+
readonly recipients?: readonly RawRecipient[];
|
|
59
|
+
readonly attachments?: readonly RawAttachment[];
|
|
60
|
+
};
|
|
61
|
+
declare const mapRawMsg: (raw: RawMsg, attachmentContents: readonly (Uint8Array | undefined)[]) => ParsedMsg;
|
|
62
|
+
type AttachmentReader = {
|
|
63
|
+
readonly getAttachment: (index: number) => {
|
|
64
|
+
readonly content?: unknown;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
type MsgReaderInstance = AttachmentReader & {
|
|
68
|
+
readonly getFileData: () => unknown;
|
|
69
|
+
};
|
|
70
|
+
type MsgReaderCtor = new (input: ArrayBuffer | DataView) => MsgReaderInstance;
|
|
71
|
+
declare const readAttachmentContent: (reader: AttachmentReader, index: number) => Uint8Array | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the MsgReader class from the dynamic import's `default`, whichever
|
|
74
|
+
* interop shape it arrives in. msgreader is CJS with `exports.default = class`
|
|
75
|
+
* (+ `__esModule`): Bun's RUNTIME import hands us the class directly, but Bun's
|
|
76
|
+
* BUNDLER (node-mode `__toESM`) sets `default` to the whole exports object —
|
|
77
|
+
* so in `dist/cli.js` the class sits one level deeper at `default.default`
|
|
78
|
+
* ("Object is not a constructor" at runtime, invisible to source-run tests).
|
|
79
|
+
*/
|
|
80
|
+
declare const resolveMsgReaderCtor: (defaultExport: unknown) => MsgReaderCtor;
|
|
81
|
+
declare const extractMsg: (bytes: Uint8Array) => Promise<Result<ParsedMsg, GraphError>>;
|
|
82
|
+
export { extractMsg, mapRawMsg, readAttachmentContent, resolveMsgReaderCtor };
|
|
83
|
+
export type { MsgAttachment, MsgRecipient, MsgRecipientKind, ParsedMsg };
|
|
@@ -3,7 +3,7 @@ export declare const BINARY_TRANSFER_TIMEOUT_MS: number;
|
|
|
3
3
|
export declare const REQUEST_TIMEOUT_LABEL = "60s";
|
|
4
4
|
export declare const BINARY_TRANSFER_TIMEOUT_LABEL = "5min";
|
|
5
5
|
export declare const networkErrorMessage: (e: unknown, label: string, timeoutLabel: string) => string;
|
|
6
|
-
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
6
|
+
export type HttpMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
7
7
|
export type TimeoutTier = 'json' | 'binary';
|
|
8
8
|
export declare const timeoutLabelFor: (tier: TimeoutTier) => string;
|
|
9
9
|
export declare const timeoutMsFor: (tier: TimeoutTier) => number;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { GraphError } from './graph-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pulls the image parts out of an OOXML package (.docx / .xlsx /
|
|
5
|
+
* .pptx and their macro-enabled / template variants). Images live as binary
|
|
6
|
+
* parts under `word/media/`, `xl/media/`, or `ppt/media/` — including
|
|
7
|
+
* original full-resolution / un-cropped originals and images on hidden
|
|
8
|
+
* slides that the rendered view never shows.
|
|
9
|
+
*
|
|
10
|
+
* Separate from `ooxml-zip-adapter` on purpose: that adapter pre-decodes
|
|
11
|
+
* every entry as a UTF-8 string (correct for XML, corrupting for binary),
|
|
12
|
+
* whereas media must come back as raw bytes. try/catch is permitted here
|
|
13
|
+
* (src/infra/**, atelier rule 17): a malformed-zip throw becomes a Result.err.
|
|
14
|
+
*
|
|
15
|
+
* Raster formats (png/jpg/gif/bmp/tiff/webp) a vision model can read directly,
|
|
16
|
+
* plus svg — the one vector format a model can use, because its XML source
|
|
17
|
+
* carries the diagram's own text labels (and modern Office embeds it as the
|
|
18
|
+
* high-fidelity original beside a png fallback). Legacy vector (emf/wmf) and
|
|
19
|
+
* audio/video are still excluded — neither a model can use.
|
|
20
|
+
*/
|
|
21
|
+
type MediaPart = {
|
|
22
|
+
readonly path: string;
|
|
23
|
+
readonly bytes: Uint8Array;
|
|
24
|
+
};
|
|
25
|
+
declare const extractOoxmlMedia: (bytes: Uint8Array) => Promise<Result<ReadonlyArray<MediaPart>, GraphError>>;
|
|
26
|
+
export { extractOoxmlMedia };
|
|
27
|
+
export type { MediaPart };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { GraphError } from './graph-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Thin wrapper around JSZip for opening already-fetched OOXML bytes
|
|
5
|
+
* (.docx / .xlsx / .pptx — all ZIP packages with a shared docProps/* core).
|
|
6
|
+
* Pure CPU on bytes already in memory — no IO — so this matches the
|
|
7
|
+
* mammoth-adapter pattern: a Result-returning factory, no port, no fake.
|
|
8
|
+
* Tests work end-to-end against real fixtures built with the `docx` /
|
|
9
|
+
* `xlsx` packages (or hand-rolled JSZip) via test-helpers/office-fixtures.ts.
|
|
10
|
+
*
|
|
11
|
+
* try/catch is permitted under src/infra/** (atelier hard rule 17): any
|
|
12
|
+
* malformed-zip throw from JSZip translates into a Result.err with a
|
|
13
|
+
* GraphError shape so callers stay on the Result rail.
|
|
14
|
+
*
|
|
15
|
+
* The returned reader is synchronous on purpose: callers in the use-case
|
|
16
|
+
* layer are pure XML walkers that don't model async/await internally.
|
|
17
|
+
* Every text entry is pre-decoded once at open time, then served from
|
|
18
|
+
* an in-memory map. `list()` exposes the entry paths so callers can
|
|
19
|
+
* enumerate numbered parts (`xl/comments1.xml`, `ppt/slides/slide*.xml`,
|
|
20
|
+
* every `*.rels`) that can't be hardcoded.
|
|
21
|
+
*/
|
|
22
|
+
type OoxmlZip = {
|
|
23
|
+
readonly read: (path: string) => string | undefined;
|
|
24
|
+
readonly list: () => ReadonlyArray<string>;
|
|
25
|
+
};
|
|
26
|
+
declare const openOoxmlZip: (bytes: Uint8Array) => Promise<Result<OoxmlZip, GraphError>>;
|
|
27
|
+
export { openOoxmlZip };
|
|
28
|
+
export type { OoxmlZip };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { GraphError } from './graph-client.js';
|
|
3
|
+
import type { MediaPart } from './ooxml-media-extractor.js';
|
|
4
|
+
/**
|
|
5
|
+
* Extract embedded raster images from a PDF via unpdf (a pure-JS pdfjs build — no
|
|
6
|
+
* native deps, runs under Bun). unpdf walks each page's painted image XObjects and
|
|
7
|
+
* returns *decoded* pixels, which we PNG-encode.
|
|
8
|
+
*
|
|
9
|
+
* Scope note: this is page-oriented — it sees images AS PAINTED on each page. It does
|
|
10
|
+
* NOT reach OCG/layer-hidden images, unpainted/orphan XObjects, or the full uncropped
|
|
11
|
+
* original behind a clipped image; capturing those needs an object-graph walk (a much
|
|
12
|
+
* heavier dependency). All PAGES are always walked (PDF has no "hidden page" concept).
|
|
13
|
+
*
|
|
14
|
+
* `try/catch` is permitted here per the infra-boundary rule: pdfjs throws on malformed
|
|
15
|
+
* input and we translate that into a Result rather than letting it escape.
|
|
16
|
+
*/
|
|
17
|
+
declare const extractPdfImages: (bytes: Uint8Array) => Promise<Result<ReadonlyArray<MediaPart>, GraphError>>;
|
|
18
|
+
export { extractPdfImages };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { GraphError } from './graph-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract a PDF's text layer via unpdf (a pure-JS pdfjs build — no native deps,
|
|
5
|
+
* runs under Bun). Returns the reading-order text of every page merged into one
|
|
6
|
+
* string. A born-digital PDF (exported from Word/LaTeX/Chrome/…) yields its text;
|
|
7
|
+
* a scanned / image-only PDF has no text layer, so the string comes back empty —
|
|
8
|
+
* callers treat that as "needs OCR / a vision model", never as success-with-text.
|
|
9
|
+
*
|
|
10
|
+
* Scope note: this is the embedded text layer, NOT OCR. It also does not preserve
|
|
11
|
+
* layout structure (headings, tables, columns flatten into reading order).
|
|
12
|
+
*
|
|
13
|
+
* `try/catch` is permitted here per the infra-boundary rule: pdfjs throws on
|
|
14
|
+
* malformed input and we translate that into a Result rather than letting it escape.
|
|
15
|
+
*
|
|
16
|
+
* `verbosity: 0` (pdfjs `VerbosityLevel.ERRORS`) silences pdfjs's TrueType
|
|
17
|
+
* font-hinting log spam — `Warning: TT: undefined function: N`, `Required "glyf"
|
|
18
|
+
* table is not found`, `Indexing all PDF objects` — which it emits via its own
|
|
19
|
+
* `console.warn` while parsing a PDF's embedded fonts. Font hinting is sub-pixel
|
|
20
|
+
* glyph rendering, completely irrelevant to text extraction (the text still comes
|
|
21
|
+
* out fine); the default level (WARNINGS) just floods the host app's logs once per
|
|
22
|
+
* quirky font. We lower it at the boundary because the noise originates inside
|
|
23
|
+
* pdfjs — the `no-console` rule keeps us from emitting or intercepting it ourselves.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Map a pdfjs throw to an actionable message. The special case is an encrypted
|
|
27
|
+
* PDF: pdfjs raises `PasswordException` ("No password given") — QA run-1 found a
|
|
28
|
+
* real tenant file surfacing that raw string with zero guidance. Password
|
|
29
|
+
* handling is genuinely unsupported (and Graph's `format=pdf` cannot unlock
|
|
30
|
+
* encrypted sources either), so say that honestly instead of leaking pdfjs
|
|
31
|
+
* internals. Pure and exported: the branch is unit-tested with shaped errors —
|
|
32
|
+
* no encrypted-PDF fixture exists in the toolchain.
|
|
33
|
+
*/
|
|
34
|
+
declare const pdfErrorMessage: (e: unknown) => string;
|
|
35
|
+
type PdfText = {
|
|
36
|
+
readonly text: string;
|
|
37
|
+
readonly pageCount: number;
|
|
38
|
+
};
|
|
39
|
+
declare const extractPdfText: (bytes: Uint8Array) => Promise<Result<PdfText, GraphError>>;
|
|
40
|
+
export { extractPdfText, pdfErrorMessage };
|
|
41
|
+
export type { PdfText };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal, dependency-free PNG encoder for raw 8-bit pixel buffers. unpdf hands
|
|
3
|
+
* back *decoded* pixels (1=grayscale, 3=RGB, 4=RGBA channels), so to write usable
|
|
4
|
+
* image files without a native dep (sharp/canvas) we wrap them in a PNG ourselves:
|
|
5
|
+
* signature + IHDR + a single zlib-compressed IDAT (filter-0 scanlines) + IEND.
|
|
6
|
+
*/
|
|
7
|
+
type RawImage = {
|
|
8
|
+
readonly width: number;
|
|
9
|
+
readonly height: number;
|
|
10
|
+
readonly channels: number;
|
|
11
|
+
readonly data: Uint8Array;
|
|
12
|
+
};
|
|
13
|
+
declare const encodePng: (image: RawImage) => Uint8Array;
|
|
14
|
+
export { encodePng };
|
|
15
|
+
export type { RawImage };
|
|
@@ -4,6 +4,6 @@ type SheetCsv = {
|
|
|
4
4
|
readonly name: string;
|
|
5
5
|
readonly csv: string;
|
|
6
6
|
};
|
|
7
|
-
declare const readSheetsAsCsv: (bytes: Uint8Array) => Result<ReadonlyArray<SheetCsv>, GraphError
|
|
7
|
+
declare const readSheetsAsCsv: (bytes: Uint8Array) => Promise<Result<ReadonlyArray<SheetCsv>, GraphError>>;
|
|
8
8
|
export { readSheetsAsCsv };
|
|
9
9
|
export type { SheetCsv };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AccessToken } from '../domain/access-token.js';
|
|
2
|
+
import type { Result } from '../domain/result.js';
|
|
3
|
+
import type { Logger } from '../use-cases/ports/logger.js';
|
|
4
|
+
type SystemBrowserAuthDeps = {
|
|
5
|
+
readonly logger: Logger;
|
|
6
|
+
readonly timeoutMs?: number;
|
|
7
|
+
readonly extensionTimeoutMs?: number;
|
|
8
|
+
};
|
|
9
|
+
type SystemBrowserTokenResult = {
|
|
10
|
+
readonly accessToken: AccessToken;
|
|
11
|
+
readonly refreshToken: string | null;
|
|
12
|
+
readonly elevatedAccessToken?: AccessToken | null;
|
|
13
|
+
readonly chatsvcaggAccessToken?: AccessToken | null;
|
|
14
|
+
readonly ic3AccessToken?: AccessToken | null;
|
|
15
|
+
readonly chatsvcaggRegion?: string;
|
|
16
|
+
};
|
|
17
|
+
type SystemBrowserAuthError = {
|
|
18
|
+
type: 'server_bind_failed';
|
|
19
|
+
message: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: 'browser_open_failed';
|
|
22
|
+
message: string;
|
|
23
|
+
} | {
|
|
24
|
+
type: 'extension_timeout';
|
|
25
|
+
message: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'invalid_token';
|
|
28
|
+
message: string;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'cancelled';
|
|
31
|
+
message: string;
|
|
32
|
+
};
|
|
33
|
+
declare const authenticateViaSystemBrowser: (deps: SystemBrowserAuthDeps) => Promise<Result<SystemBrowserTokenResult, SystemBrowserAuthError>>;
|
|
34
|
+
export { authenticateViaSystemBrowser };
|
|
35
|
+
export type { SystemBrowserAuthDeps, SystemBrowserAuthError, SystemBrowserTokenResult };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { Logger } from '../use-cases/ports/logger.js';
|
|
3
|
+
type TokenCallbackPayload = {
|
|
4
|
+
readonly access_token: string;
|
|
5
|
+
readonly refresh_token?: string;
|
|
6
|
+
readonly elevated_access_token?: string;
|
|
7
|
+
readonly chatsvcagg_access_token?: string;
|
|
8
|
+
readonly ic3_access_token?: string;
|
|
9
|
+
readonly chatsvcagg_region?: string;
|
|
10
|
+
};
|
|
11
|
+
type TokenCallbackServer = {
|
|
12
|
+
readonly port: number;
|
|
13
|
+
readonly start: () => Promise<Result<TokenCallbackPayload, TokenCallbackError>>;
|
|
14
|
+
readonly stop: () => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
type TokenCallbackError = {
|
|
17
|
+
type: 'bind_failed';
|
|
18
|
+
message: string;
|
|
19
|
+
} | {
|
|
20
|
+
type: 'timeout';
|
|
21
|
+
message: string;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'invalid_payload';
|
|
24
|
+
message: string;
|
|
25
|
+
} | {
|
|
26
|
+
type: 'server_closed';
|
|
27
|
+
message: string;
|
|
28
|
+
};
|
|
29
|
+
declare const createTokenCallbackServer: (logger: Logger, timeoutMs?: number) => TokenCallbackServer;
|
|
30
|
+
export { createTokenCallbackServer };
|
|
31
|
+
export type { TokenCallbackError, TokenCallbackPayload, TokenCallbackServer };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Result } from '../domain/result.js';
|
|
2
|
+
import type { GraphError } from './graph-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reads every file entry out of an arbitrary `.zip` archive as raw bytes,
|
|
5
|
+
* sorted by path, directories excluded. Generic counterpart to
|
|
6
|
+
* `ooxml-media-extractor` (which matches only media paths) and
|
|
7
|
+
* `ooxml-zip-adapter` (which decodes entries as UTF-8 strings) — used by the
|
|
8
|
+
* zip-conversion commands to fan each contained file out to the right
|
|
9
|
+
* converter. try/catch is permitted here (src/infra/**, atelier rule 17): a
|
|
10
|
+
* malformed-zip throw becomes a Result.err.
|
|
11
|
+
*/
|
|
12
|
+
type ZipEntry = {
|
|
13
|
+
readonly path: string;
|
|
14
|
+
readonly bytes: Uint8Array;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Decode a legacy zip entry name — the raw filename bytes of an entry whose
|
|
18
|
+
* UTF-8 flag (general-purpose bit 11) is NOT set and which carries no Info-ZIP
|
|
19
|
+
* Unicode-path extra field. JSZip's default decoder assumes UTF-8 and mojibakes
|
|
20
|
+
* these (the `unzip -O GBK` case): Chinese vendor archives written by WinRAR /
|
|
21
|
+
* Windows Explorer store names in GBK. Try strict UTF-8 first (some archivers
|
|
22
|
+
* emit UTF-8 bytes without setting the flag), then fall back to GB18030 — a GBK
|
|
23
|
+
* superset whose 0x00–0x7F bytes are plain ASCII, so legacy ASCII/CP437 names
|
|
24
|
+
* survive unchanged while CJK byte sequences decode correctly.
|
|
25
|
+
*
|
|
26
|
+
* Only reached for non-UTF-8-flagged names (JSZip handles UTF-8 names itself),
|
|
27
|
+
* so a UTF-8 archive's path-handling is unchanged.
|
|
28
|
+
*/
|
|
29
|
+
declare const decodeZipFileName: (bytes: Uint8Array) => string;
|
|
30
|
+
declare const openZipEntries: (bytes: Uint8Array) => Promise<Result<ReadonlyArray<ZipEntry>, GraphError>>;
|
|
31
|
+
export { decodeZipFileName, openZipEntries };
|
|
32
|
+
export type { ZipEntry };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Translate Graph / substrate / CLI / validation errors into actionable hints.
|
|
3
3
|
*
|
|
4
|
-
* Audit
|
|
4
|
+
* Audit Jane-session §2: 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,7 +12,7 @@
|
|
|
12
12
|
* `--output text` (as `hint:` / `source:` lines under the existing `error:`
|
|
13
13
|
* line).
|
|
14
14
|
*
|
|
15
|
-
* Audit
|
|
15
|
+
* Audit Jane-session §2 follow-up: the four error-envelope variants are
|
|
16
16
|
* - `graph` — public Microsoft Graph API at /v1.0/
|
|
17
17
|
* - `substrate` — Microsoft-internal chat substrates (chatsvcagg / IC3).
|
|
18
18
|
* Tagged at the infra layer with `substrateHttp{N}_{name}`.
|
|
@@ -2,6 +2,6 @@ import type { Logger } from '../use-cases/ports/logger.js';
|
|
|
2
2
|
import type { ErrorSource } from './error-hints.js';
|
|
3
3
|
type OutputFormat = 'text' | 'json';
|
|
4
4
|
declare const render: (data: unknown, logger: Logger, format: OutputFormat) => void;
|
|
5
|
-
declare const renderError: (message: string, format: OutputFormat, errorCode?: string, explicitSource?: ErrorSource) => void;
|
|
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 };
|
|
@@ -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. Audit
|
|
10
|
+
* `--select` always wins. Audit Jane-session §A: 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
|
*/
|
|
@@ -80,6 +80,14 @@ type PaginationStrategy =
|
|
|
80
80
|
type CommandMeta = {
|
|
81
81
|
readonly summary: string;
|
|
82
82
|
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>;
|
|
83
91
|
readonly graphMethod: CommandHttpMethod;
|
|
84
92
|
readonly graphPathTemplate: string;
|
|
85
93
|
readonly graphDocsUrl: string;
|
|
@@ -107,6 +115,14 @@ type CommandMeta = {
|
|
|
107
115
|
* commands will time out.
|
|
108
116
|
*/
|
|
109
117
|
readonly needsElevatedToken?: true;
|
|
118
|
+
/**
|
|
119
|
+
* `true` if the command needs a Teams substrate token (chatsvcagg or ic3,
|
|
120
|
+
* captured at login from `teams.microsoft.com`) — the Teams chat-content
|
|
121
|
+
* commands. Like `needsElevatedToken`, an LLM should check this before
|
|
122
|
+
* invoking and warm up an interactive `login`; a headless or stale session
|
|
123
|
+
* times out on these (the non-interactive silent-SSO limitation, QA-011).
|
|
124
|
+
*/
|
|
125
|
+
readonly needsSubstrateToken?: true;
|
|
110
126
|
/**
|
|
111
127
|
* `true` if the command returns inlined bytes (`{contentType, size, base64}`
|
|
112
128
|
* or `{contentType, size, text}`) and is therefore a valid target for the
|
|
@@ -115,6 +131,24 @@ type CommandMeta = {
|
|
|
115
131
|
* as a string literal. Audit round-8 Wave E2.
|
|
116
132
|
*/
|
|
117
133
|
readonly producesBytes?: true;
|
|
134
|
+
/**
|
|
135
|
+
* `true` if the command returns a `media` array (`{ count, media: [{ path,
|
|
136
|
+
* contentType, sizeBytes, base64 }] }`) and is therefore a valid target for
|
|
137
|
+
* the global `--output-dir` flag, which writes each image to a directory.
|
|
138
|
+
* Parallel to `producesBytes` (single-file `--output-path`).
|
|
139
|
+
*/
|
|
140
|
+
readonly producesMedia?: true;
|
|
141
|
+
/**
|
|
142
|
+
* `true` if the command performs a write (mutation) against Microsoft Graph
|
|
143
|
+
* rather than a read/search. Today only the two mail-draft commands
|
|
144
|
+
* (`create-mail-draft` = POST, `update-mail-draft` = PATCH) — both produce an
|
|
145
|
+
* UNSENT draft and cannot send. The CLI composition derives its read-only
|
|
146
|
+
* top-level `--help` narrative from this flag (mutating commands vs search
|
|
147
|
+
* POSTs) instead of hardcoding command names, and the manifest/`help-json`
|
|
148
|
+
* surface it so an LLM can tell at a glance which commands change state.
|
|
149
|
+
* Audit 2026-06-15 (F-03).
|
|
150
|
+
*/
|
|
151
|
+
readonly mutates?: true;
|
|
118
152
|
/**
|
|
119
153
|
* Stability tier of the command. Omitted from manifest entries when the
|
|
120
154
|
* command is `'stable'` (the implicit default), surfaced only on
|
|
@@ -123,7 +157,7 @@ type CommandMeta = {
|
|
|
123
157
|
* substrate (chatsvcagg / IC3) that is not in the public Graph API and can
|
|
124
158
|
* break on a Teams web-client update — the docstring "Best-effort, may break
|
|
125
159
|
* on Microsoft client updates" warnings now have a structured pair.
|
|
126
|
-
* Audit
|
|
160
|
+
* Audit Jane-session §6.
|
|
127
161
|
*/
|
|
128
162
|
readonly stability?: 'experimental';
|
|
129
163
|
};
|
|
@@ -131,5 +165,12 @@ type Command = {
|
|
|
131
165
|
readonly schema: CommandSchema;
|
|
132
166
|
readonly execute: CommandExecute;
|
|
133
167
|
readonly meta: CommandMeta;
|
|
168
|
+
/**
|
|
169
|
+
* 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
|
|
171
|
+
* composition-selected FileSystem; `execute` stays as the registry-typed
|
|
172
|
+
* fallback that redirects library consumers to this variant.
|
|
173
|
+
*/
|
|
174
|
+
readonly executeLocal?: (fs: import('../ports/filesystem.js').FileSystem, params: Record<string, string>) => Promise<Result<unknown, import('../../infra/graph-client.js').GraphError>>;
|
|
134
175
|
};
|
|
135
176
|
export type { ArgumentHint, Command, CommandCategory, CommandExecute, CommandHttpMethod, CommandMeta, CommandOptionAlias, CommandOptionMeta, CommandPositionalArgumentMeta, CommandSchema, PaginationStrategy, };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Result } from '../../domain/result.js';
|
|
3
|
+
import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
4
|
+
import type { CommandMeta } from './command-types.js';
|
|
5
|
+
declare const schema: z.ZodObject<{
|
|
6
|
+
eventId: z.ZodString;
|
|
7
|
+
attachmentId: z.ZodString;
|
|
8
|
+
includeMetadata: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
true: "true";
|
|
10
|
+
false: "false";
|
|
11
|
+
}>>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
14
|
+
declare const meta: CommandMeta;
|
|
15
|
+
export { execute, meta, schema };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Result } from '../../domain/result.js';
|
|
3
|
+
import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
4
|
+
import type { CommandMeta } from './command-types.js';
|
|
5
|
+
declare const schema: z.ZodObject<{
|
|
6
|
+
eventId: z.ZodString;
|
|
7
|
+
attachmentId: z.ZodString;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
10
|
+
declare const meta: CommandMeta;
|
|
11
|
+
export { execute, meta, schema };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Result } from '../../domain/result.js';
|
|
3
|
+
import type { GraphClient, GraphError } from '../../infra/graph-client.js';
|
|
4
|
+
import type { CommandMeta } from './command-types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Unzips a `.zip` from a OneDrive / SharePoint item and runs each contained
|
|
7
|
+
* file through the same local conversion pipelines the `*-as-markdown` commands
|
|
8
|
+
* use — so an agent reading "the project handover archive" doesn't have to shell
|
|
9
|
+
* out to `unzip` and convert each file separately. Office files (docx/xlsx/pptx/
|
|
10
|
+
* odt/ods/odp + variants) become markdown; legacy OLE .xls / .doc are extracted
|
|
11
|
+
* too (.ppt is noted, no pure-JS path); plain-text entries are decoded inline;
|
|
12
|
+
* PDFs have their text layer extracted; everything else (images, binaries, nested
|
|
13
|
+
* archives — plus scanned/image-only PDFs and legacy .ppt) is listed with a note
|
|
14
|
+
* rather than failing the whole archive.
|
|
15
|
+
*/
|
|
16
|
+
declare const schema: z.ZodObject<{
|
|
17
|
+
driveId: z.ZodString;
|
|
18
|
+
itemId: z.ZodString;
|
|
19
|
+
includeMetadata: z.ZodOptional<z.ZodEnum<{
|
|
20
|
+
true: "true";
|
|
21
|
+
false: "false";
|
|
22
|
+
}>>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
declare const execute: (graph: GraphClient, params: Record<string, string>) => Promise<Result<unknown, GraphError>>;
|
|
25
|
+
declare const meta: CommandMeta;
|
|
26
|
+
export { execute, meta, schema };
|