@griffinwork40/outlook-cli 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/env.ts","../src/errors.ts","../src/args.ts","../src/config.ts","../src/types.ts","../src/identityFetch.ts","../src/deviceCode.ts","../src/auth.ts","../src/client.ts","../src/flagSpec.ts","../src/redact.ts","../src/tokenStore.ts","../src/scopes.ts","../src/commands/attachments.ts","../src/dryRun.ts","../src/policyGuard.ts","../src/policy.ts","../src/command.ts","../src/mime.ts","../src/output.ts","../src/paginate.ts","../src/safeFilename.ts","../src/commands/auth.ts","../src/commands/contacts.ts","../src/signature.ts","../src/commands/compose.ts","../src/commands/draft.ts","../src/commands/flags.ts","../src/commands/folders.ts","../src/commands/get.ts","../src/commands/list.ts","../src/commands/me.ts","../src/commands/move.ts","../src/commands/replyDraft.ts","../src/commands/reply.ts","../src/commands/rules.ts","../src/commands/search.ts","../src/commands/send.ts"],"sourcesContent":["/**\n * `outlook` — the CLI entrypoint.\n *\n * Three jobs, and deliberately nothing else:\n * 1. Route argv[0] to a CommandSpec.\n * 2. Build the single CommandContext every command binds to. This is the\n * ONLY place the real `fetch` and the real on-disk token cache are\n * supplied — everything below takes them by injection, which is what\n * lets the whole command layer be tested without a network.\n * 3. Own the one error -> exit-code boundary, so no command ever calls\n * process.exit and every message is redacted exactly once on its way out.\n *\n * Exit codes: 0 ok | 1 unexpected | 2 usage | 3 auth/config | 4 policy refusal\n * (see errors.ts).\n */\n\nimport { createRequire } from 'node:module';\n\nimport { loadEnvFile } from './env.js';\n\n// Load ~/.afk/config/afk.env before anything reads process.env — agent\n// sessions may not have GRAPH_CLIENT_ID exported in the shell profile.\nloadEnvFile();\n\nimport type { ParsedArgs } from './args.js';\nimport { parseArgs } from './args.js';\nimport { createAuthenticator } from './auth.js';\nimport { GraphClient } from './client.js';\nimport type { CommandContext, CommandSpec } from './command.js';\nimport { resolveConfig } from './config.js';\nimport { OutlookCliError, UsageError } from './errors.js';\nimport { assertKnownFlags } from './flagSpec.js';\nimport { redactText } from './redact.js';\nimport { createTokenStore } from './tokenStore.js';\n\nimport { attachmentsCommand } from './commands/attachments.js';\nimport { authCommand } from './commands/auth.js';\nimport { contactsCommand } from './commands/contacts.js';\nimport { draftCommand } from './commands/draft.js';\nimport {\n flagCommand,\n markReadCommand,\n markUnreadCommand,\n unflagCommand,\n} from './commands/flags.js';\nimport { foldersCommand } from './commands/folders.js';\nimport { getCommand } from './commands/get.js';\nimport { listCommand } from './commands/list.js';\nimport { meCommand } from './commands/me.js';\nimport { deleteCommand, moveCommand, purgeCommand } from './commands/move.js';\nimport {\n forwardCommand,\n replyAllCommand,\n replyCommand,\n} from './commands/reply.js';\nimport { rulesCommand } from './commands/rules.js';\nimport { searchCommand } from './commands/search.js';\nimport { sendCommand } from './commands/send.js';\n\nconst COMMANDS: readonly CommandSpec[] = [\n authCommand,\n meCommand,\n listCommand,\n getCommand,\n searchCommand,\n foldersCommand,\n attachmentsCommand,\n contactsCommand,\n sendCommand,\n replyCommand,\n replyAllCommand,\n forwardCommand,\n draftCommand,\n moveCommand,\n deleteCommand,\n purgeCommand,\n markReadCommand,\n markUnreadCommand,\n flagCommand,\n unflagCommand,\n rulesCommand,\n];\n\nconst REGISTRY = new Map<string, CommandSpec>(\n COMMANDS.map((command) => [command.name, command]),\n);\n\n/** Help groupings. Names are resolved through REGISTRY, never duplicated. */\nconst GROUPS: readonly { title: string; names: readonly string[] }[] = [\n { title: 'Auth & identity', names: ['auth', 'me'] },\n {\n title: 'Read',\n names: ['list', 'get', 'search', 'folders', 'attachments'],\n },\n {\n title: 'People',\n names: ['contacts'],\n },\n {\n title: 'Send',\n names: ['send', 'reply', 'reply-all', 'forward', 'draft'],\n },\n {\n title: 'Organize',\n names: [\n 'move',\n 'delete',\n 'purge',\n 'mark-read',\n 'mark-unread',\n 'flag',\n 'unflag',\n 'rules',\n ],\n },\n];\n\nfunction packageVersion(): string {\n try {\n const pkg = createRequire(import.meta.url)('../package.json') as {\n version?: string;\n };\n return pkg.version ?? '0.0.0';\n } catch {\n return '0.0.0';\n }\n}\n\nfunction helpText(): string {\n const lines: string[] = [\n 'outlook — Microsoft Graph Outlook Mail from the command line',\n '',\n 'Usage: outlook <command> [options]',\n '',\n ];\n\n for (const group of GROUPS) {\n lines.push(`${group.title}:`);\n for (const name of group.names) {\n const command = REGISTRY.get(name);\n if (command === undefined) continue;\n const flag = command.mutating ? ' [--dry-run]' : '';\n lines.push(` ${name.padEnd(13)} ${command.summary}${flag}`);\n }\n lines.push('');\n }\n\n lines.push(\n 'Global options:',\n ' --json Machine-readable output',\n ' --dry-run On a mutating command: print the request, send nothing',\n ' -h, --help This help, or `outlook <command> --help`',\n ' -V, --version Print the version',\n '',\n 'Environment:',\n ' OUTLOOK_POLICY=<file> Restrict mutations to a JSON policy (README: Restricted agent mode)',\n '',\n 'First run: export GRAPH_CLIENT_ID=<azure-app-id> && outlook auth login',\n 'Setup walkthrough: SETUP.md',\n '',\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Wire the real dependencies. `getToken` is passed as a thunk so the client\n * asks the authenticator for a token per attempt — that is what makes a\n * mid-flight refresh transparent to every command.\n *\n * Note: config resolution requires GRAPH_CLIENT_ID for every command,\n * including `auth logout`. That is intentional — one code path, and the\n * MissingCredentialsError already names the variable and points at SETUP.md.\n */\nfunction buildContext(args: ParsedArgs, commandName: string): CommandContext {\n const config = resolveConfig(process.env);\n const store = createTokenStore(config.tokenCachePath);\n const auth = createAuthenticator(config, store);\n const client = new GraphClient({\n getToken: () => auth.getAccessToken(),\n });\n\n return {\n args,\n json: args.bool('json'),\n dryRun: args.bool('dry-run'),\n command: commandName,\n client,\n auth,\n env: process.env,\n out: (line: string) => {\n process.stdout.write(`${line}\\n`);\n },\n err: (line: string) => {\n process.stderr.write(`${line}\\n`);\n },\n };\n}\n\nasync function run(argv: string[]): Promise<number> {\n const first = argv[0];\n\n if (first === undefined || first === 'help' || first === '--help' || first === '-h') {\n process.stdout.write(helpText());\n return 0;\n }\n if (first === 'version' || first === '--version' || first === '-V') {\n process.stdout.write(`${packageVersion()}\\n`);\n return 0;\n }\n\n const command = REGISTRY.get(first);\n if (command === undefined) {\n throw new UsageError(\n `Unknown command: ${first}\\n\\nRun 'outlook help' for the command list.`,\n );\n }\n\n const rest = argv.slice(1);\n const args = parseArgs(rest);\n\n if (args.bool('help') || args.bool('h')) {\n process.stdout.write(`${command.summary}\\n\\n${command.usage}\\n`);\n return 0;\n }\n\n // Fail closed on a misspelled flag BEFORE any context is built or any\n // handler runs. A typo'd --dry-run must never reach a mutating command.\n assertKnownFlags(command.name, args.names());\n\n const ctx = buildContext(args, command.name);\n\n // A no-op --dry-run should say so rather than imply something was withheld.\n if (ctx.dryRun && !command.mutating) {\n ctx.err(\n `note: '${command.name}' does not change anything, so --dry-run has no effect.`,\n );\n }\n\n await command.handler(ctx);\n return 0;\n}\n\nfunction reportFailure(error: unknown): number {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`${redactText(message)}\\n`);\n return error instanceof OutlookCliError ? error.exitCode : 1;\n}\n\n// Set process.exitCode rather than calling process.exit(), so buffered\n// stdout is never truncated mid-write on a piped or redirected run.\ntry {\n process.exitCode = await run(process.argv.slice(2));\n} catch (error) {\n process.exitCode = reportFailure(error);\n}\n","/**\n * Auto-load environment variables from `~/.afk/config/afk.env`.\n *\n * Agent sessions often lack exported GRAPH_CLIENT_ID because the shell\n * profile was never sourced. SETUP.md tells users to persist it into this\n * file, but the CLI never read it — until now.\n *\n * Rules:\n * 1. If the file does not exist → no-op (not an error).\n * 2. Lines starting with `#` (after trimming) are comments → skip.\n * 3. Blank lines → skip.\n * 4. Lines matching `KEY=value` (with optional surrounding quotes on the\n * value — single or double) set `process.env[KEY]` **only if that key\n * is not already set**. Existing env vars always win.\n *\n * Zero runtime dependencies — uses only `node:fs` and `node:os`.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst ENV_PATH = join(homedir(), '.afk', 'config', 'afk.env');\n\n/**\n * Parse lines from a `.env`-style file and return key-value pairs.\n * Exported for testing; the main API is `loadEnvFile`.\n */\nexport function parseEnvLines(content: string): [string, string][] {\n const pairs: [string, string][] = [];\n for (const raw of content.split('\\n')) {\n const line = raw.trim();\n if (line === '' || line.startsWith('#')) continue;\n\n const eqIdx = line.indexOf('=');\n if (eqIdx === -1) continue;\n\n const key = line.slice(0, eqIdx).trim();\n if (key === '') continue;\n\n let value = line.slice(eqIdx + 1).trim();\n // Strip matched surrounding quotes (single or double).\n if (\n value.length >= 2 &&\n ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\")))\n ) {\n value = value.slice(1, -1);\n }\n\n pairs.push([key, value]);\n }\n return pairs;\n}\n\n/**\n * Read `~/.afk/config/afk.env` and inject any missing keys into\n * `process.env`. An explicit `envPath` can be supplied for testing.\n */\nexport function loadEnvFile(envPath: string = ENV_PATH): void {\n let content: string;\n try {\n content = readFileSync(envPath, 'utf-8');\n } catch {\n // File doesn't exist or isn't readable — nothing to do.\n return;\n }\n\n for (const [key, value] of parseEnvLines(content)) {\n if (process.env[key] === undefined) {\n process.env[key] = value;\n }\n }\n}\n","/**\n * Error taxonomy. Every error carries an exit code so cli.ts can map\n * failures to shell semantics without re-inspecting types.\n *\n * Exit codes:\n * 1 — runtime/API failure\n * 2 — usage error (bad flags, missing args)\n * 3 — missing credentials / not authenticated\n * 4 — refused by the OUTLOOK_POLICY mutation policy\n */\n\nexport class OutlookCliError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = 'OutlookCliError';\n this.exitCode = exitCode;\n }\n}\n\n/** A required env var is absent. Names the exact var and points at SETUP.md. */\nexport class MissingCredentialsError extends OutlookCliError {\n readonly missing: readonly string[];\n\n constructor(missing: readonly string[]) {\n const list = missing.join(', ');\n super(\n `Missing required environment variable(s): ${list}\\n` +\n `\\nGRAPH_CLIENT_ID comes from a one-time Azure app registration.\\n` +\n `See SETUP.md for the 5-step click-path, then export it:\\n` +\n ` export GRAPH_CLIENT_ID=<application-client-id>`,\n 3,\n );\n this.name = 'MissingCredentialsError';\n this.missing = missing;\n }\n}\n\n/** No cached token, or the cached token is unusable and cannot be refreshed. */\nexport class NotAuthenticatedError extends OutlookCliError {\n constructor(detail?: string) {\n super(\n `Not signed in${detail ? `: ${detail}` : '.'}\\n` +\n `\\nRun: outlook auth login`,\n 3,\n );\n this.name = 'NotAuthenticatedError';\n }\n}\n\n/**\n * The cached grant is read-only and the command needs to change the mailbox.\n * Caught locally, before the request goes out, so a least-privilege session\n * fails with an actionable message instead of an opaque Graph 403.\n */\nexport class InsufficientScopeError extends OutlookCliError {\n constructor(action: string) {\n super(\n `This session was signed in with --readonly, so it cannot ${action}.\\n` +\n `\\nRe-authorize with full access: outlook auth login`,\n 3,\n );\n this.name = 'InsufficientScopeError';\n }\n}\n\n/**\n * A mutation refused by the OUTLOOK_POLICY file (policy.ts). Its own exit code\n * so an unattended caller can tell \"the guard said no\" from a Graph failure\n * and stop instead of retrying. `rule` names the policy clause that fired.\n */\nexport class PolicyRefusedError extends OutlookCliError {\n readonly rule: string;\n\n constructor(rule: string, reason: string) {\n super(`Refused by mutation policy (${rule}): ${reason}`, 4);\n this.name = 'PolicyRefusedError';\n this.rule = rule;\n }\n}\n\n/** Bad flags or arguments. */\nexport class UsageError extends OutlookCliError {\n constructor(message: string) {\n super(message, 2);\n this.name = 'UsageError';\n }\n}\n\n/** A non-2xx response from Graph or the identity platform. */\nexport class GraphError extends OutlookCliError {\n readonly status: number;\n readonly code: string;\n readonly graphMessage: string;\n readonly requestId?: string;\n readonly retryAfter?: number;\n\n constructor(params: {\n status: number;\n code: string;\n message: string;\n requestId?: string;\n retryAfter?: number;\n }) {\n const hint = GRAPH_ERROR_HINTS[params.code];\n super(\n `Graph API error ${params.status} (${params.code}): ${params.message}` +\n (hint ? `\\n → ${hint}` : '') +\n (params.requestId ? `\\n request-id: ${params.requestId}` : ''),\n 1,\n );\n this.name = 'GraphError';\n this.status = params.status;\n this.code = params.code;\n this.graphMessage = params.message;\n this.requestId = params.requestId;\n this.retryAfter = params.retryAfter;\n }\n}\n\n/**\n * Operational translation of the Graph error codes a mail CLI actually hits\n * (docs/00 §8). Keyed on error.code — never on error.message, which is\n * human-facing prose Microsoft reserves the right to change.\n */\nexport const GRAPH_ERROR_HINTS: Record<string, string> = {\n InvalidAuthenticationToken:\n 'Access token expired or malformed. Run: outlook auth login',\n ErrorAccessDenied:\n 'The signed-in account lacks permission. Confirm the Mail.ReadWrite / Mail.Send scopes were consented at login.',\n ErrorItemNotFound:\n 'No message with that id. Note: message ids change when a message moves between folders unless immutable ids are used.',\n ErrorInvalidUser: 'The mailbox does not exist or is not licensed for mail.',\n ErrorInvalidRecipients:\n 'One or more recipient addresses were rejected. Check for typos and that each is a routable address.',\n ErrorMessageSizeExceeded:\n 'Message plus attachments exceeded the mailbox send limit. Use fewer or smaller attachments.',\n ErrorAttachmentSizeExceeded:\n 'Inline attachments must be under 3 MB. Larger files need an upload session (not supported in v1).',\n ErrorMailboxStoreUnavailable:\n 'The mailbox is temporarily unavailable. Retry shortly.',\n ErrorQuotaExceeded: 'Mailbox is over quota.',\n ErrorFolderNotFound:\n 'No folder with that name or id. Run: outlook folders list',\n ErrorInvalidIdMalformed:\n 'That id is not a valid Graph id. Ids are opaque — copy them verbatim from a list/get.',\n InefficientFilter:\n 'The $filter/$orderby combination is too complex. Properties in $orderby must also appear in $filter, in the same order.',\n activityLimitReached:\n 'Throttled by Outlook (429). The client backs off automatically; if this persists, reduce request volume.',\n TooManyRequests: 'Throttled by Outlook (429). Back off and retry.',\n ErrorTooManyObjectsOpened:\n 'Too many concurrent mailbox operations. Reduce concurrency to 4 or fewer.',\n ErrorSendAsDenied:\n 'The account may not send as that address. Check Send As permissions.',\n MailboxNotEnabledForRESTAPI:\n 'This mailbox cannot be accessed via the REST API (often an on-prem or unlicensed mailbox).',\n};\n\n/** Parse a Graph error envelope defensively — both innerError casings occur. */\nexport function parseGraphError(\n status: number,\n bodyText: string,\n retryAfter?: number,\n): GraphError {\n let code = `HTTP${status}`;\n let message = bodyText.slice(0, 500) || 'no response body';\n let requestId: string | undefined;\n\n try {\n const parsed: unknown = JSON.parse(bodyText);\n const root = parsed as {\n error?: unknown;\n error_description?: unknown;\n };\n\n // Identity-platform errors use flat {error, error_description} strings;\n // Graph errors nest an object under `error`. Handle both.\n if (typeof root.error === 'string') {\n code = root.error;\n if (typeof root.error_description === 'string') {\n message = root.error_description;\n }\n } else if (root.error && typeof root.error === 'object') {\n const err = root.error as {\n code?: unknown;\n message?: unknown;\n innerError?: Record<string, unknown>;\n innererror?: Record<string, unknown>;\n };\n if (typeof err.code === 'string') code = err.code;\n if (typeof err.message === 'string') message = err.message;\n const inner = err.innerError ?? err.innererror;\n const rid = inner?.['request-id'] ?? inner?.['client-request-id'];\n if (typeof rid === 'string') requestId = rid;\n }\n } catch {\n // Non-JSON body (HTML error page, empty 502). Keep the raw slice.\n }\n\n return new GraphError({ status, code, message, requestId, retryAfter });\n}\n","/**\n * Dependency-free argv parser.\n *\n * Convention (no schema is passed in, so this is deliberately simple and\n * documented rather than \"smart\"): a bare `--flag` greedily consumes the\n * following token as its string value UNLESS that token looks like another\n * flag (starts with `-`, length > 1) or is the `--` terminator. This means a\n * boolean-style flag immediately followed by a positional the caller wants\n * kept separate (e.g. `outlook list --json inbox`) will swallow \"inbox\" as\n * `--json`'s value rather than leaving it positional. `.bool()` still comes\n * back `true` in that case (presence-based), but the positional is lost.\n * Callers should order positionals before trailing boolean flags (the usual\n * CLI convention: `outlook list inbox --json`) or use `--` to force a hard\n * boundary. This tradeoff is inherent to schema-less argv parsing (the same\n * ambiguity minimist has) and is called out here rather than silently\n * assumed.\n */\n\nimport { UsageError } from './errors.js';\n\nexport interface ParsedArgs {\n positionals: string[];\n raw: string[];\n has(name: string): boolean;\n str(name: string, fallback?: string): string | undefined;\n strAll(name: string): string[];\n num(name: string): number | undefined;\n bool(name: string): boolean;\n require(name: string): string;\n requirePositional(index: number, label: string): string;\n /** Every flag name seen on the command line. Drives unknown-flag rejection. */\n names(): string[];\n}\n\ntype FlagValue = string | boolean;\n\n/**\n * Explicit boolean spellings accepted by `.bool()`. Anything else supplied as\n * a value to a boolean flag is a UsageError rather than a silent coercion —\n * see the `bool` implementation for why that matters for `--yes`.\n */\nconst TRUE_VALUES = new Set(['true', '1', 'yes', 'on']);\nconst FALSE_VALUES = new Set(['false', '0', 'no', 'off', '']);\n\n/** `-` alone is treated as a value (common \"stdin\" convention), not a flag. */\nfunction looksLikeOption(tok: string | undefined): boolean {\n if (tok === undefined) return false;\n if (tok === '-') return false;\n return tok.startsWith('-') && tok.length > 1;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const positionals: string[] = [];\n const store = new Map<string, FlagValue[]>();\n\n function record(name: string, value: FlagValue): void {\n const existing = store.get(name);\n if (existing) existing.push(value);\n else store.set(name, [value]);\n }\n\n let i = 0;\n let terminated = false;\n\n while (i < argv.length) {\n const tok = argv[i];\n if (tok === undefined) break;\n\n if (!terminated && tok === '--') {\n terminated = true;\n i++;\n continue;\n }\n\n if (terminated) {\n positionals.push(tok);\n i++;\n continue;\n }\n\n if (tok.startsWith('--') && tok.length > 2) {\n const body = tok.slice(2);\n const eq = body.indexOf('=');\n\n if (eq !== -1) {\n record(body.slice(0, eq), body.slice(eq + 1));\n i++;\n continue;\n }\n\n if (body.startsWith('no-') && body.length > 3) {\n record(body.slice(3), false);\n i++;\n continue;\n }\n\n const next = argv[i + 1];\n if (next !== undefined && !looksLikeOption(next)) {\n record(body, next);\n i += 2;\n continue;\n }\n\n record(body, true);\n i++;\n continue;\n }\n\n if (tok.startsWith('-') && tok.length > 1) {\n const body = tok.slice(1);\n const eq = body.indexOf('=');\n\n if (eq !== -1) {\n record(body.slice(0, eq), body.slice(eq + 1));\n i++;\n continue;\n }\n\n const next = argv[i + 1];\n if (next !== undefined && !looksLikeOption(next)) {\n record(body, next);\n i += 2;\n continue;\n }\n\n record(body, true);\n i++;\n continue;\n }\n\n positionals.push(tok);\n i++;\n }\n\n function lastValue(name: string): FlagValue | undefined {\n const list = store.get(name);\n if (!list || list.length === 0) return undefined;\n return list[list.length - 1];\n }\n\n const api: ParsedArgs = {\n positionals,\n raw: [...argv],\n\n has(name) {\n return store.has(name);\n },\n\n str(name, fallback) {\n const v = lastValue(name);\n return typeof v === 'string' ? v : fallback;\n },\n\n strAll(name) {\n const list = store.get(name);\n if (!list) return [];\n return list.filter((v): v is string => typeof v === 'string');\n },\n\n num(name) {\n const v = lastValue(name);\n if (v === undefined) return undefined;\n if (typeof v === 'boolean') {\n throw new UsageError(`--${name} requires a numeric value`);\n }\n if (v.trim() === '') {\n throw new UsageError(`--${name} expects a numeric value, got \"\"`);\n }\n const n = Number(v);\n if (Number.isNaN(n)) {\n throw new UsageError(`--${name} expects a numeric value, got \"${v}\"`);\n }\n return n;\n },\n\n /**\n * Presence-based, but NEVER value-blind.\n *\n * The old implementation returned `last !== false`, which meant any string\n * value was truthy — so `--yes=false` (a user trying to DECLINE an\n * irreversible purge) read as `true` and the deletion proceeded. Explicit\n * false spellings must win, and anything ambiguous must be a loud error\n * rather than a guess, because the guess that gets this wrong deletes\n * mail. A bare `--flag` is still `true`; `--no-flag` is still `false`.\n */\n bool(name) {\n const v = lastValue(name);\n if (v === undefined) return false;\n if (typeof v === 'boolean') return v;\n\n const normalized = v.trim().toLowerCase();\n if (TRUE_VALUES.has(normalized)) return true;\n if (FALSE_VALUES.has(normalized)) return false;\n\n // Almost always the schema-less greedy-consumption footgun documented at\n // the top of this file: `outlook list --json inbox` swallowed \"inbox\".\n // That used to silently drop the positional; now it says so.\n throw new UsageError(\n `--${name} does not take a value (got \"${v}\").\\n` +\n `If \"${v}\" is a positional argument, put it before the flag: ` +\n `\\`... ${v} --${name}\\`.`,\n );\n },\n\n require(name) {\n const v = lastValue(name);\n if (typeof v === 'string') return v;\n throw new UsageError(`Missing required flag: --${name}`);\n },\n\n requirePositional(index, label) {\n const v = positionals[index];\n if (v === undefined) {\n throw new UsageError(`Missing required argument: ${label}`);\n }\n return v;\n },\n\n names() {\n return [...store.keys()];\n },\n };\n\n return api;\n}\n","/**\n * Configuration resolution. Env is injected (never read from the global\n * `process` inside library code) so tests can drive it directly.\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { MissingCredentialsError } from './errors.js';\nimport type { OutlookConfig } from './types.js';\n\nexport type ConfigNeed = 'clientId' | 'clientSecret';\n\nexport interface EnvLike {\n [key: string]: string | undefined;\n}\n\n/** Default token cache: ~/.afk/state/outlook/token.json */\nexport function defaultTokenCachePath(env: EnvLike = {}): string {\n const override = trimmed(env['GRAPH_TOKEN_CACHE']);\n if (override) return override;\n const afkHome = trimmed(env['AFK_HOME']) ?? join(homedir(), '.afk');\n return join(afkHome, 'state', 'outlook', 'token.json');\n}\n\n/**\n * Resolve config from env, failing loud with the exact missing var names.\n * `needs` lets read-only paths (e.g. `auth status`) avoid demanding a secret.\n */\nexport function resolveConfig(\n env: EnvLike,\n needs: readonly ConfigNeed[] = ['clientId'],\n): OutlookConfig {\n const missing: string[] = [];\n\n const clientId = trimmed(env['GRAPH_CLIENT_ID']);\n if (needs.includes('clientId') && !clientId) {\n missing.push('GRAPH_CLIENT_ID');\n }\n\n const clientSecret = trimmed(env['GRAPH_CLIENT_SECRET']);\n if (needs.includes('clientSecret') && !clientSecret) {\n missing.push('GRAPH_CLIENT_SECRET');\n }\n\n if (missing.length > 0) {\n throw new MissingCredentialsError(missing);\n }\n\n return {\n clientId: clientId ?? '',\n tenantId: trimmed(env['GRAPH_TENANT_ID']) ?? 'common',\n ...(clientSecret ? { clientSecret } : {}),\n tokenCachePath: defaultTokenCachePath(env),\n };\n}\n\n/** Identity-platform base for this tenant. */\nexport function authorityBase(tenantId: string): string {\n return `https://login.microsoftonline.com/${encodeURIComponent(tenantId)}/oauth2/v2.0`;\n}\n\nfunction trimmed(value: string | undefined): string | undefined {\n if (typeof value !== 'string') return undefined;\n const t = value.trim();\n return t.length > 0 ? t : undefined;\n}\n","/**\n * Microsoft Graph v1.0 resource shapes — the subset this CLI touches.\n * Sourced from docs/01-read-endpoints.md and docs/02-write-endpoints.md.\n */\n\nexport interface EmailAddress {\n address: string;\n name?: string;\n}\n\nexport interface Recipient {\n emailAddress: EmailAddress;\n}\n\n/**\n * Graph accepts both \"Text\"/\"HTML\" and \"text\"/\"html\" on write and echoes\n * lowercase on read. We author lowercase everywhere (docs/02).\n */\nexport type BodyContentType = 'text' | 'html';\n\nexport interface ItemBody {\n contentType: BodyContentType;\n content: string;\n}\n\nexport type FlagStatus = 'notFlagged' | 'flagged' | 'complete';\n\nexport interface FollowupFlag {\n flagStatus: FlagStatus;\n}\n\nexport type Importance = 'low' | 'normal' | 'high';\n\nexport interface Message {\n id: string;\n subject?: string | null;\n bodyPreview?: string;\n body?: ItemBody;\n from?: Recipient | null;\n sender?: Recipient | null;\n toRecipients?: Recipient[];\n ccRecipients?: Recipient[];\n bccRecipients?: Recipient[];\n replyTo?: Recipient[];\n receivedDateTime?: string;\n sentDateTime?: string;\n hasAttachments?: boolean;\n isRead?: boolean;\n isDraft?: boolean;\n importance?: Importance;\n flag?: FollowupFlag;\n parentFolderId?: string;\n conversationId?: string;\n webLink?: string;\n internetMessageId?: string;\n}\n\n/** Fields writable when creating or updating a draft (docs/02 §3). */\nexport interface DraftInput {\n subject?: string;\n body?: ItemBody;\n toRecipients?: Recipient[];\n ccRecipients?: Recipient[];\n bccRecipients?: Recipient[];\n importance?: Importance;\n}\n\nexport interface MailFolder {\n id: string;\n displayName: string;\n parentFolderId?: string;\n childFolderCount?: number;\n unreadItemCount?: number;\n totalItemCount?: number;\n}\n\nexport type AttachmentODataType =\n | '#microsoft.graph.fileAttachment'\n | '#microsoft.graph.itemAttachment'\n | '#microsoft.graph.referenceAttachment';\n\nexport interface Attachment {\n id: string;\n name: string;\n contentType?: string | null;\n size?: number;\n isInline?: boolean;\n lastModifiedDateTime?: string;\n '@odata.type'?: AttachmentODataType | string;\n /** base64 — present on fileAttachment when fetched directly. */\n contentBytes?: string;\n}\n\n/** Body shape for POSTing an inline attachment (< 3 MB, docs/02 §6). */\nexport interface FileAttachmentUpload {\n '@odata.type': '#microsoft.graph.fileAttachment';\n name: string;\n contentType: string;\n contentBytes: string;\n}\n\nexport interface UserProfile {\n id: string;\n displayName?: string;\n mail?: string | null;\n userPrincipalName?: string;\n jobTitle?: string | null;\n}\n\n/**\n * Microsoft Graph v1.0 contact resource (GET /me/contacts).\n * Users must re-login (`outlook auth logout && outlook auth login`) to\n * pick up the new Contacts.Read scope after upgrading to this version.\n */\nexport interface Contact {\n id: string;\n displayName?: string | null;\n givenName?: string | null;\n surname?: string | null;\n emailAddresses?: EmailAddress[];\n mobilePhone?: string | null;\n businessPhones?: string[];\n homePhones?: string[];\n companyName?: string | null;\n jobTitle?: string | null;\n department?: string | null;\n personalNotes?: string | null;\n}\n\n/** Envelope returned by every Graph collection endpoint. */\nexport interface GraphCollection<T> {\n '@odata.context'?: string;\n '@odata.nextLink'?: string;\n '@odata.count'?: number;\n value: T[];\n}\n\n/** Graph error envelope (docs/00 §8). Note both innerError casings occur. */\nexport interface GraphErrorBody {\n error: {\n code: string;\n message: string;\n innerError?: Record<string, unknown>;\n innererror?: Record<string, unknown>;\n };\n}\n\n/**\n * Well-known folder names usable in place of a folder id (docs/01 §2).\n * Verified against user-list-mailfolders.\n */\nexport const WELL_KNOWN_FOLDERS = [\n 'archive',\n 'clutter',\n 'conflicts',\n 'conversationhistory',\n 'deleteditems',\n 'drafts',\n 'inbox',\n 'junkemail',\n 'localfailures',\n 'msgfolderroot',\n 'outbox',\n 'recoverableitemsdeletions',\n 'scheduled',\n 'searchfolders',\n 'sentitems',\n 'serverfailures',\n 'syncissues',\n] as const;\n\nexport type WellKnownFolder = (typeof WELL_KNOWN_FOLDERS)[number];\n\nexport function isWellKnownFolder(name: string): boolean {\n return (WELL_KNOWN_FOLDERS as readonly string[]).includes(name.toLowerCase());\n}\n\n/** OAuth2 token set as persisted to the local 0600 cache. */\n/**\n * Which scope set this grant was obtained with.\n *\n * Tracked explicitly rather than inferred from the `scope` string Azure echoes\n * back, because that echo lists resource scopes and generally omits\n * `offline_access` — refreshing against it would quietly cost us the rotated\n * refresh token. Absent on a token issued before read-only mode existed, which\n * is read as 'full' so an existing login keeps working untouched.\n */\nexport type GrantMode = 'readonly' | 'full';\n\nexport interface TokenSet {\n accessToken: string;\n refreshToken?: string;\n /** Epoch milliseconds. */\n expiresAt: number;\n scope?: string;\n tokenType?: string;\n /** Signed-in identity, for `auth status`. */\n account?: string;\n mode?: GrantMode;\n /**\n * The exact scope set requested by `auth login --scopes`. When present,\n * refresh re-requests exactly this set instead of scopesForMode(mode), so a\n * narrow grant stays narrow. Absent for default and --readonly logins.\n */\n grantScopes?: string[];\n}\n\n/** Response from the /devicecode endpoint (docs/00 §2). */\nexport interface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n expires_in: number;\n interval: number;\n message?: string;\n}\n\n/** Response from the /token endpoint (docs/00 §3, §4). */\nexport interface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope?: string;\n token_type?: string;\n id_token?: string;\n}\n\n/** A fully-described Graph request, used for --dry-run rendering. */\nexport interface RequestSpec {\n method: string;\n url: string;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n/** Resolved runtime configuration. */\nexport interface OutlookConfig {\n clientId: string;\n tenantId: string;\n clientSecret?: string;\n tokenCachePath: string;\n}\n\nexport const GRAPH_BASE = 'https://graph.microsoft.com/v1.0';\n\n/**\n * Hard ceiling on a single HTTP attempt, shared by every outbound call —\n * Graph requests and the identity-platform credential exchanges alike. Without\n * it a hung socket hangs the CLI indefinitely, which for the unattended agent\n * this tool is built for is a stall with no operator present to notice it.\n *\n * Per ATTEMPT, never per operation: the device-code poll legitimately runs for\n * the lifetime of the code, so each of its requests gets its own fresh timeout\n * rather than one deadline around the loop.\n */\nexport const REQUEST_TIMEOUT_MS = 60_000;\n\n/**\n * Full grant requested by a plain `outlook auth login`.\n *\n * Calendars.Read, Files.Read.All and Sites.Read.All are read-only grants that\n * let the same token read calendar events and search/download OneDrive and\n * SharePoint files through Graph (/search/query, /drives/{id}/items/{id}/content).\n * Files.Read.All and Sites.Read.All typically need tenant admin consent on work\n * accounts (see SETUP.md). Users must re-login to pick up newly added scopes.\n */\nexport const DEFAULT_SCOPES = [\n 'offline_access',\n 'User.Read',\n 'Mail.ReadWrite',\n 'Mail.Send',\n 'MailboxSettings.ReadWrite',\n 'Contacts.Read',\n 'Calendars.Read',\n 'Files.Read.All',\n 'Sites.Read.All',\n] as const;\n\n/**\n * Least-privilege alternative for `outlook auth login --readonly`.\n *\n * Mail.Read replaces Mail.ReadWrite and Mail.Send is dropped entirely, so the\n * refresh token this grant persists cannot send, delete, or modify mail even\n * if the token file is stolen. Agents that only ever list/search/read should\n * use it: the default grant's blast radius is the whole mailbox, forever,\n * because `offline_access` keeps it alive.\n */\nexport const READONLY_SCOPES = [\n 'offline_access',\n 'User.Read',\n 'Mail.Read',\n 'MailboxSettings.Read',\n] as const;\n\nexport function scopesForMode(mode: GrantMode): readonly string[] {\n return mode === 'readonly' ? READONLY_SCOPES : DEFAULT_SCOPES;\n}\n","/**\n * The single place a credential is POSTed to the identity platform.\n *\n * auth.ts (the refresh-token exchange) and deviceCode.ts (the device-code\n * request and the token poll) all send a secret in the request BODY — a\n * `refresh_token` or a `device_code`. client.ts already refuses to follow a\n * redirect for exactly this reason, but its guard covers the Graph host only,\n * and these three calls never touch it.\n *\n * A 307/308 preserves the method AND the body, so a redirected credential\n * exchange replays the secret to whichever origin answered. The cross-origin\n * `Authorization`-stripping that fetch does for free is no help here: the\n * secret is not in a header. Hence `redirect: 'error'` — the identity platform\n * does not redirect these endpoints, so a 3xx is hostile, not routine.\n *\n * Routing all three through one function means a fourth call site cannot\n * reintroduce the hole by assembling its own fetch init. Same reasoning that\n * puts the bearer-host check inside client.ts's `send()` rather than in\n * `buildUrl`, and `--dry-run` inside `guardMutation` rather than in each\n * command.\n */\n\nimport { REQUEST_TIMEOUT_MS } from './types.js';\n\nconst FORM_HEADERS = { 'Content-Type': 'application/x-www-form-urlencoded' };\n\nexport function postForm(\n url: string,\n params: URLSearchParams,\n fetchImpl: typeof fetch,\n): Promise<Response> {\n return fetchImpl(url, {\n method: 'POST',\n headers: FORM_HEADERS,\n body: params.toString(),\n redirect: 'error',\n // Per ATTEMPT, deliberately not per operation: the device-code poll\n // legitimately runs for the lifetime of the code, so each request inside\n // that loop gets a fresh timeout rather than sharing one deadline.\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n}\n","/**\n * OAuth2 device code flow — initiate + poll. Endpoint URLs, the grant_type\n * URN, and the five polling error codes are all specified verbatim in\n * docs/00-auth-and-fundamentals.md §2-§3. Nothing here is guessed.\n *\n * No network or real timers are hardwired: both `fetchImpl` and `sleep` are\n * injectable so tests run instantly against a fake transport.\n */\n\nimport { authorityBase } from './config.js';\nimport { OutlookCliError, parseGraphError } from './errors.js';\nimport { postForm } from './identityFetch.js';\nimport type { DeviceCodeResponse, OutlookConfig, TokenResponse } from './types.js';\n\n/**\n * The device-code grant_type value, copied character-for-character from\n * docs/00 §3 (verified there against RFC 8628 §3.4's own registered URN —\n * there is no shorthand form; `device_code` alone fails).\n */\nexport const DEVICE_CODE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';\n\n/** docs/00 §2: devicecode response default; not a guaranteed contract, just the observed default. */\nconst DEFAULT_EXPIRES_IN_SEC = 900;\n/** docs/00 §2: \"Observed value in practice: 5.\" Used only when the caller has no better value. */\nconst DEFAULT_POLL_INTERVAL_SEC = 5;\n/** docs/00 §3 + §9.1: on `slow_down`, permanently add 5s to the interval. */\nconst SLOW_DOWN_INCREMENT_MS = 5_000;\n\nexport async function requestDeviceCode(\n cfg: OutlookConfig,\n scopes: readonly string[],\n fetchImpl: typeof fetch = fetch,\n): Promise<DeviceCodeResponse> {\n const url = `${authorityBase(cfg.tenantId)}/devicecode`;\n const params = new URLSearchParams({\n client_id: cfg.clientId,\n scope: scopes.join(' '),\n });\n\n const res = await postForm(url, params, fetchImpl);\n const bodyText = await res.text().catch(() => '');\n\n if (!res.ok) {\n throw parseGraphError(res.status, bodyText);\n }\n\n const parsed = parseJsonSafe(bodyText);\n if (!isDeviceCodeResponse(parsed)) {\n throw new OutlookCliError(\n 'The devicecode endpoint returned a 200 response with an unrecognized body shape.',\n );\n }\n return parsed;\n}\n\nexport interface PollForTokenOptions {\n /** Seconds between polls. Default: the devicecode response's own `interval`, or 5. */\n intervalSec?: number;\n /** Hard deadline in seconds. Default: the devicecode response's own `expires_in`, or 900. */\n expiresInSec?: number;\n fetchImpl?: typeof fetch;\n /** Injectable so tests advance instantly instead of waiting on real timers. */\n sleep?: (ms: number) => Promise<void>;\n}\n\nexport async function pollForToken(\n cfg: OutlookConfig,\n deviceCode: string,\n opts: PollForTokenOptions = {},\n): Promise<TokenResponse> {\n const fetchImpl = opts.fetchImpl ?? fetch;\n const sleep = opts.sleep ?? defaultSleep;\n const deadlineMs = (opts.expiresInSec ?? DEFAULT_EXPIRES_IN_SEC) * 1000;\n let intervalMs = (opts.intervalSec ?? DEFAULT_POLL_INTERVAL_SEC) * 1000;\n\n const url = `${authorityBase(cfg.tenantId)}/token`;\n const params = new URLSearchParams({\n grant_type: DEVICE_CODE_GRANT_TYPE,\n client_id: cfg.clientId,\n device_code: deviceCode,\n });\n\n // Virtual clock: driven by the sleep durations we actually request, not\n // wall time. This keeps the hard-deadline check meaningful under a fake\n // `sleep` that resolves instantly in tests, while still enforcing the\n // real accounting an un-mocked run would experience.\n let elapsedMs = 0;\n\n for (;;) {\n const res = await postForm(url, params, fetchImpl);\n const bodyText = await res.text().catch(() => '');\n\n if (res.ok) {\n const parsed = parseJsonSafe(bodyText);\n if (!isTokenResponse(parsed)) {\n throw new OutlookCliError(\n 'The token endpoint returned a 200 response with an unrecognized body shape.',\n );\n }\n return parsed;\n }\n\n const code = extractErrorCode(bodyText);\n switch (code) {\n case 'authorization_pending':\n break;\n case 'slow_down':\n intervalMs += SLOW_DOWN_INCREMENT_MS;\n break;\n case 'expired_token':\n throw new OutlookCliError(\n 'The device code expired before sign-in was completed. Run login again.',\n );\n case 'authorization_declined':\n throw new OutlookCliError('Sign-in was declined.');\n case 'bad_verification_code':\n throw new OutlookCliError(\n 'The device code was not recognized by the server. This should not happen in normal ' +\n 'operation — it indicates a bug in the polling loop, not a transient condition.',\n );\n default:\n // Any other error (invalid_client, invalid_request, ...) is fatal\n // and carries real diagnostic detail — surface it verbatim.\n throw parseGraphError(res.status, bodyText);\n }\n\n if (elapsedMs + intervalMs >= deadlineMs) {\n throw new OutlookCliError(\n 'The device code expired before sign-in was completed (local deadline reached). Run login again.',\n );\n }\n\n await sleep(intervalMs);\n elapsedMs += intervalMs;\n }\n}\n\nfunction parseJsonSafe(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/** Only the `error` field's string value is a stable contract (docs/00 §3). */\nfunction extractErrorCode(bodyText: string): string | undefined {\n const parsed = parseJsonSafe(bodyText);\n if (parsed !== null && typeof parsed === 'object' && 'error' in parsed) {\n const value = (parsed as Record<string, unknown>)['error'];\n if (typeof value === 'string') return value;\n }\n return undefined;\n}\n\nfunction isDeviceCodeResponse(value: unknown): value is DeviceCodeResponse {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v['device_code'] === 'string' &&\n typeof v['user_code'] === 'string' &&\n typeof v['verification_uri'] === 'string' &&\n typeof v['expires_in'] === 'number' &&\n typeof v['interval'] === 'number' &&\n (v['message'] === undefined || typeof v['message'] === 'string')\n );\n}\n\nfunction isTokenResponse(value: unknown): value is TokenResponse {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v['access_token'] === 'string' &&\n typeof v['expires_in'] === 'number' &&\n (v['refresh_token'] === undefined || typeof v['refresh_token'] === 'string') &&\n (v['scope'] === undefined || typeof v['scope'] === 'string') &&\n (v['token_type'] === undefined || typeof v['token_type'] === 'string') &&\n (v['id_token'] === undefined || typeof v['id_token'] === 'string')\n );\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Token acquisition, refresh, and status — the surface the CLI's commands\n * actually call. Wraps deviceCode.ts (initiate + poll) and tokenStore.ts\n * (disk cache) behind a single `Authenticator`.\n *\n * Refresh-token rotation (docs/00 §4) is load-bearing: Microsoft may return\n * a NEW refresh token on every refresh call, and the old one can be silently\n * invalidated once that happens. Every refresh here persists whatever\n * refresh_token comes back — never the one that was just spent.\n */\n\nimport { authorityBase } from './config.js';\nimport { NotAuthenticatedError, OutlookCliError, parseGraphError } from './errors.js';\nimport { requestDeviceCode, pollForToken } from './deviceCode.js';\nimport { postForm } from './identityFetch.js';\nimport type { TokenStore } from './tokenStore.js';\nimport type {\n DeviceCodeResponse,\n GrantMode,\n OutlookConfig,\n TokenResponse,\n TokenSet,\n} from './types.js';\nimport { scopesForMode } from './types.js';\n\n/** getAccessToken refreshes proactively once the token is this close to expiry. */\nconst REFRESH_SKEW_MS = 60_000;\n\nexport interface AuthStatus {\n signedIn: boolean;\n account?: string;\n expiresAt?: number;\n expired: boolean;\n scopes?: string;\n /** Absent on a pre-existing token issued before read-only mode existed. */\n mode?: GrantMode;\n /** Present only when the session was signed in with `--scopes`. */\n grantScopes?: string[];\n}\n\nexport interface LoginOptions {\n /** Request the reduced scope set — cannot send, delete, or modify mail. */\n readOnly?: boolean;\n /**\n * Request exactly these scopes (already normalized by parseScopeList, so\n * `offline_access` is included). Mutually exclusive with readOnly.\n */\n scopes?: readonly string[];\n}\n\nexport interface Authenticator {\n getAccessToken(): Promise<string>;\n login(\n onPrompt: (d: DeviceCodeResponse) => void,\n opts?: LoginOptions,\n ): Promise<TokenSet>;\n logout(): Promise<void>;\n refresh(): Promise<TokenSet>;\n status(): Promise<AuthStatus>;\n}\n\nexport interface AuthenticatorDeps {\n fetchImpl?: typeof fetch;\n sleep?: (ms: number) => Promise<void>;\n /** Injectable clock so expiry math is deterministic in tests. */\n now?: () => number;\n}\n\nexport function createAuthenticator(\n cfg: OutlookConfig,\n store: TokenStore,\n deps: AuthenticatorDeps = {},\n): Authenticator {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? defaultSleep;\n const now = deps.now ?? Date.now;\n\n async function refresh(): Promise<TokenSet> {\n const cached = await store.load();\n if (!cached) throw new NotAuthenticatedError();\n if (!cached.refreshToken) {\n throw new NotAuthenticatedError('cached session has no refresh token; run login again');\n }\n\n // Refresh with the scope set this grant was ORIGINALLY obtained under.\n // Hardcoding DEFAULT_SCOPES here would ask Azure to upgrade a read-only\n // session to full read/write on its next refresh, silently undoing the\n // least-privilege choice the user made at login. A `--scopes` login\n // records its exact set in grantScopes, which wins over the mode default.\n const mode = cached.mode ?? 'full';\n const scopes = cached.grantScopes ?? scopesForMode(mode);\n const tokenResponse = await exchangeRefreshToken(\n cfg,\n cached.refreshToken,\n scopes,\n fetchImpl,\n );\n const nextTokens = toTokenSet(tokenResponse, now(), cached);\n await store.save(nextTokens);\n return nextTokens;\n }\n\n return {\n async getAccessToken(): Promise<string> {\n const cached = await store.load();\n if (!cached) throw new NotAuthenticatedError();\n\n if (cached.expiresAt - now() < REFRESH_SKEW_MS) {\n const refreshed = await refresh();\n return refreshed.accessToken;\n }\n return cached.accessToken;\n },\n\n async login(\n onPrompt: (d: DeviceCodeResponse) => void,\n opts: LoginOptions = {},\n ): Promise<TokenSet> {\n const mode: GrantMode = opts.readOnly ? 'readonly' : 'full';\n const custom = opts.scopes !== undefined ? [...opts.scopes] : undefined;\n const deviceCode = await requestDeviceCode(\n cfg,\n custom ?? scopesForMode(mode),\n fetchImpl,\n );\n onPrompt(deviceCode);\n\n const tokenResponse = await pollForToken(cfg, deviceCode.device_code, {\n intervalSec: deviceCode.interval,\n expiresInSec: deviceCode.expires_in,\n fetchImpl,\n sleep,\n });\n\n const tokens: TokenSet = {\n ...toTokenSet(tokenResponse, now()),\n mode,\n ...(custom !== undefined ? { grantScopes: custom } : {}),\n };\n await store.save(tokens);\n return tokens;\n },\n\n async logout(): Promise<void> {\n await store.clear();\n },\n\n refresh,\n\n async status(): Promise<AuthStatus> {\n const cached = await store.load();\n if (!cached) return { signedIn: false, expired: false };\n\n return {\n signedIn: true,\n expired: now() >= cached.expiresAt,\n expiresAt: cached.expiresAt,\n ...(cached.account !== undefined ? { account: cached.account } : {}),\n ...(cached.scope !== undefined ? { scopes: cached.scope } : {}),\n ...(cached.mode !== undefined ? { mode: cached.mode } : {}),\n ...(cached.grantScopes !== undefined ? { grantScopes: cached.grantScopes } : {}),\n };\n },\n };\n}\n\n/** docs/00 §4: same /token endpoint, grant_type=refresh_token, no client_secret for a public client. */\nasync function exchangeRefreshToken(\n cfg: OutlookConfig,\n refreshToken: string,\n scopes: readonly string[],\n fetchImpl: typeof fetch,\n): Promise<TokenResponse> {\n const url = `${authorityBase(cfg.tenantId)}/token`;\n const params = new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: cfg.clientId,\n refresh_token: refreshToken,\n scope: scopes.join(' '),\n });\n\n const res = await postForm(url, params, fetchImpl);\n const bodyText = await res.text().catch(() => '');\n\n if (!res.ok) {\n throw parseGraphError(res.status, bodyText);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyText);\n } catch {\n throw new OutlookCliError(\n 'The token endpoint returned a 200 response with an unparseable body during refresh.',\n );\n }\n if (!isTokenResponse(parsed)) {\n throw new OutlookCliError(\n 'The token endpoint returned a 200 response with an unrecognized body shape during refresh.',\n );\n }\n return parsed;\n}\n\n/**\n * Builds the TokenSet to persist. Rotation contract: `refresh_token` from\n * THIS response wins whenever present; we fall back to `previous`'s only\n * when the server omitted one on this call (still oscillates toward the\n * newest token Microsoft has issued, never re-sends a stale one).\n */\nfunction toTokenSet(\n tokenResponse: TokenResponse,\n nowMs: number,\n previous?: TokenSet,\n): TokenSet {\n const account = tokenResponse.id_token\n ? (decodeIdTokenAccount(tokenResponse.id_token) ?? previous?.account)\n : previous?.account;\n const refreshToken = tokenResponse.refresh_token ?? previous?.refreshToken;\n const scope = tokenResponse.scope ?? previous?.scope;\n const tokenType = tokenResponse.token_type ?? previous?.tokenType;\n // The grant mode is OURS, not Azure's — the token response never echoes it,\n // so it can only survive a refresh by being carried forward here. Dropping\n // it would silently re-escalate: the next refresh would read `mode ?? 'full'`\n // and ask for the full scope set, and guardMutation's read-only gate would\n // stop firing. A --readonly session must stay read-only across refreshes.\n const mode = previous?.mode;\n // Same for a custom scope set: drop it and the next refresh asks for\n // DEFAULT_SCOPES, widening a deliberately narrow grant.\n const grantScopes = previous?.grantScopes;\n\n return {\n accessToken: tokenResponse.access_token,\n expiresAt: nowMs + tokenResponse.expires_in * 1000,\n ...(refreshToken !== undefined ? { refreshToken } : {}),\n ...(scope !== undefined ? { scope } : {}),\n ...(tokenType !== undefined ? { tokenType } : {}),\n ...(account !== undefined ? { account } : {}),\n ...(mode !== undefined ? { mode } : {}),\n ...(grantScopes !== undefined ? { grantScopes } : {}),\n };\n}\n\n/**\n * Best-effort account resolution from an id_token's payload claims.\n * Signature is NEVER verified here — this is display metadata only, not an\n * authorization decision, and the token itself is discarded after this call\n * (TokenSet has no id_token field; nothing derived from it is ever logged).\n */\nfunction decodeIdTokenAccount(idToken: string): string | undefined {\n try {\n const parts = idToken.split('.');\n if (parts.length !== 3) return undefined;\n const payloadSegment = parts[1];\n if (!payloadSegment) return undefined;\n\n const json = Buffer.from(payloadSegment, 'base64url').toString('utf8');\n const claims: unknown = JSON.parse(json);\n if (typeof claims !== 'object' || claims === null) return undefined;\n\n const c = claims as Record<string, unknown>;\n const candidates = [c['preferred_username'], c['email'], c['upn'], c['name']];\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.length > 0) return candidate;\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isTokenResponse(value: unknown): value is TokenResponse {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n return typeof v['access_token'] === 'string' && typeof v['expires_in'] === 'number';\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Fetch wrapper for Microsoft Graph. Handles auth injection, the\n * Prefer/Content-Type headers, 429/503/504 backoff, and the Graph error\n * envelope. Retry policy is the safety-critical part of this file — see\n * docs/02-write-endpoints.md §8: sendMail/reply/replyAll/forward/draft-send\n * have no documented idempotency guarantee, so a blindly-retried POST can\n * double-send a real email. This client NEVER auto-retries POST.\n */\n\nimport { GRAPH_BASE, REQUEST_TIMEOUT_MS, type RequestSpec } from './types.js';\nimport { OutlookCliError, parseGraphError } from './errors.js';\n\n/**\n * Refusal to send a credentialed request somewhere it does not belong.\n * Not a UsageError — the offending URL is server-supplied data (an\n * `@odata.nextLink`), not something the user typed.\n */\nexport class UntrustedUrlError extends OutlookCliError {\n constructor(message: string) {\n super(message, 1);\n this.name = 'UntrustedUrlError';\n }\n}\n\nexport interface GraphClientDeps {\n /** Supplies a fresh bearer token per attempt. Never imported from auth.ts here — DI only. */\n getToken: () => Promise<string>;\n fetchImpl?: typeof fetch;\n sleep?: (ms: number) => Promise<void>;\n /** Default: GRAPH_BASE from types.ts. */\n baseUrl?: string;\n /**\n * Retries allowed *after* the initial attempt, for idempotent verbs only\n * (GET/DELETE/PATCH) on 429/503/504. Default 4 ⇒ up to 5 total attempts.\n */\n maxRetries?: number;\n}\n\n/** docs/02 §8: only these verbs are safe to retry on a transient failure. */\nconst RETRYABLE_METHODS = new Set(['GET', 'DELETE', 'PATCH']);\n/** 429 (throttling, docs/00 §7) plus the two transient gateway statuses named in the brief. */\nconst RETRYABLE_STATUSES = new Set([429, 503, 504]);\nconst DEFAULT_MAX_RETRIES = 4;\nconst BASE_BACKOFF_MS = 500;\nconst MAX_BACKOFF_MS = 30_000;\nconst ABSOLUTE_URL_RE = /^https?:\\/\\//i;\n\nexport class GraphClient {\n private readonly getToken: () => Promise<string>;\n private readonly fetchImpl: typeof fetch;\n private readonly sleep: (ms: number) => Promise<void>;\n private readonly baseUrl: string;\n private readonly maxRetries: number;\n /** Derived from baseUrl, so a national-cloud endpoint stays configurable. */\n private readonly allowedHost: string;\n\n constructor(deps: GraphClientDeps) {\n this.getToken = deps.getToken;\n this.fetchImpl = deps.fetchImpl ?? fetch;\n this.sleep = deps.sleep ?? defaultSleep;\n this.baseUrl = deps.baseUrl ?? GRAPH_BASE;\n this.maxRetries = deps.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.allowedHost = new URL(this.baseUrl).host;\n }\n\n /**\n * Pure request-spec builder — no `getToken()` call, no network. This is\n * what `--dry-run` renders. Authorization is attached later, only inside\n * the actual send path.\n */\n buildSpec(\n method: string,\n path: string,\n body?: unknown,\n query?: Record<string, unknown>,\n ): RequestSpec {\n const upperMethod = method.toUpperCase();\n const url = this.buildUrl(path, query);\n const headers: Record<string, string> = {};\n\n if (upperMethod === 'GET') {\n // Keeps message/attachment ids stable across folder moves (docs/01 §8).\n headers['Prefer'] = 'IdType=\"ImmutableId\"';\n }\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n const spec: RequestSpec = { method: upperMethod, url, headers };\n if (body !== undefined) spec.body = body;\n return spec;\n }\n\n async request<T>(spec: RequestSpec): Promise<T> {\n const res = await this.executeWithRetry(spec);\n return parseSuccessBody<T>(res);\n }\n\n /** Raw Response, for binary reads (e.g. attachment/$value download). */\n async raw(spec: RequestSpec): Promise<Response> {\n return this.executeWithRetry(spec);\n }\n\n async get<T>(\n path: string,\n query?: Record<string, string | number | boolean | undefined>,\n ): Promise<T> {\n return this.request<T>(this.buildSpec('GET', path, undefined, query));\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(this.buildSpec('POST', path, body));\n }\n\n async patch<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(this.buildSpec('PATCH', path, body));\n }\n\n async del(path: string): Promise<void> {\n await this.request<void>(this.buildSpec('DELETE', path));\n }\n\n /**\n * The single place a bearer token is attached to an outbound request — and\n * therefore the only correct place to decide whether this URL is allowed to\n * receive one.\n *\n * `buildUrl` passes an absolute `path` straight through so a server-issued\n * `@odata.nextLink` can be followed verbatim. That link is response data: a\n * spoofed, MITM'd, or malformed one pointing at `http://attacker.example`\n * previously received the live mailbox token, in cleartext, and a stolen\n * Graph token replays against real Graph regardless of who presents it.\n * Validating here rather than in `buildUrl` means no future caller can\n * reintroduce the hole by constructing a spec some other way.\n */\n private assertTokenMayBeSent(url: string): void {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new UntrustedUrlError(`Refusing to send credentials to a malformed URL: ${url}`);\n }\n\n if (parsed.protocol !== 'https:') {\n throw new UntrustedUrlError(\n `Refusing to send credentials over ${parsed.protocol}// — HTTPS is required (${url})`,\n );\n }\n if (parsed.host !== this.allowedHost) {\n throw new UntrustedUrlError(\n `Refusing to send credentials to '${parsed.host}' — ` +\n `only '${this.allowedHost}' is authorized for this client.`,\n );\n }\n }\n\n private async send(spec: RequestSpec): Promise<Response> {\n this.assertTokenMayBeSent(spec.url);\n\n const token = await this.getToken();\n const headers: Record<string, string> = {\n ...(spec.headers ?? {}),\n Authorization: `Bearer ${token}`,\n };\n const init: RequestInit = {\n method: spec.method,\n headers,\n // A 3xx to another origin would otherwise replay the Authorization\n // header there. Graph does not redirect its API responses; treat one as\n // hostile rather than following it.\n redirect: 'error',\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n };\n if (spec.body !== undefined) {\n init.body = JSON.stringify(spec.body);\n }\n return this.fetchImpl(spec.url, init);\n }\n\n private async executeWithRetry(spec: RequestSpec): Promise<Response> {\n const method = spec.method.toUpperCase();\n const retryEligible = RETRYABLE_METHODS.has(method);\n let attempt = 0;\n\n for (;;) {\n const res = await this.send(spec);\n if (res.ok) return res;\n\n const willRetry =\n retryEligible && RETRYABLE_STATUSES.has(res.status) && attempt < this.maxRetries;\n\n if (!willRetry) {\n const bodyText = await res.text().catch(() => '');\n const retryAfter = parseRetryAfterSeconds(res.headers.get('retry-after'));\n throw parseGraphError(res.status, bodyText, retryAfter);\n }\n\n const delayMs = computeDelayMs(res.headers.get('retry-after'), attempt);\n await this.sleep(delayMs);\n attempt += 1;\n }\n }\n\n private buildUrl(path: string, query?: Record<string, unknown>): string {\n const isAbsolute = ABSOLUTE_URL_RE.test(path);\n const base = isAbsolute ? path : joinUrl(this.baseUrl, path);\n\n // An absolute `path` is (by contract) a server-issued @odata.nextLink\n // that already carries its own fully-encoded query string — appending\n // more query params here would be the classic re-prefix/double-query bug.\n if (isAbsolute || !query) return base;\n\n const qs = buildQueryString(query);\n if (!qs) return base;\n return `${base}${base.includes('?') ? '&' : '?'}${qs}`;\n }\n}\n\nfunction joinUrl(base: string, path: string): string {\n const trimmedBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n return `${trimmedBase}${normalizedPath}`;\n}\n\n/**\n * OData system params ($filter, $select, $top, ...) conventionally keep a\n * literal `$` — percent-encoding it to `%24` is legal but pointlessly\n * obscures the request and mismatches every Graph doc example verbatim\n * (\"must NOT be over-encoded into uselessness\"). Values are always encoded.\n */\nfunction buildQueryString(query: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, rawValue] of Object.entries(query)) {\n if (rawValue === undefined || rawValue === null) continue;\n parts.push(`${encodeQueryKey(key)}=${encodeURIComponent(String(rawValue))}`);\n }\n return parts.join('&');\n}\n\nfunction encodeQueryKey(key: string): string {\n return key.startsWith('$') ? `$${encodeURIComponent(key.slice(1))}` : encodeURIComponent(key);\n}\n\n/** Retry-After is documented in seconds (docs/00 §7); defend against an HTTP-date form too. */\nfunction parseRetryAfterSeconds(header: string | null): number | undefined {\n if (header == null) return undefined;\n const trimmed = header.trim();\n if (trimmed.length === 0) return undefined;\n\n const asNumber = Number(trimmed);\n if (Number.isFinite(asNumber) && asNumber >= 0) return asNumber;\n\n const asDate = Date.parse(trimmed);\n if (!Number.isNaN(asDate)) {\n return Math.max(0, (asDate - Date.now()) / 1000);\n }\n return undefined;\n}\n\nfunction computeDelayMs(retryAfterHeader: string | null, attempt: number): number {\n const seconds = parseRetryAfterSeconds(retryAfterHeader);\n if (seconds !== undefined) return seconds * 1000;\n return fullJitterBackoffMs(attempt);\n}\n\n/** Full-jitter exponential backoff, capped ~30s, for the no-Retry-After case. */\nfunction fullJitterBackoffMs(attempt: number): number {\n const cap = Math.min(MAX_BACKOFF_MS, BASE_BACKOFF_MS * 2 ** attempt);\n return Math.random() * cap;\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function parseSuccessBody<T>(res: Response): Promise<T> {\n if (res.status === 204) return undefined as T;\n const text = await res.text();\n if (!text) return undefined as T;\n try {\n return JSON.parse(text) as T;\n } catch {\n // A non-JSON 2xx body shouldn't happen against Graph, but never crash on it.\n return undefined as T;\n }\n}\n","/**\n * The set of flags each command accepts, and the rejection of everything else.\n *\n * Why this exists: the argv parser is deliberately schema-less, so it records\n * whatever the user typed under whatever name they typed. Nothing downstream\n * ever asked \"is that a real flag?\", which meant a typo was indistinguishable\n * from an omission. The consequence was not cosmetic:\n *\n * outlook send --to a@b.com --subject S --body B --dryrun\n *\n * parses `dryrun`, nobody reads `dryrun`, `ctx.dryRun` is therefore false, the\n * guardMutation chokepoint is skipped, and the mail is really sent. One missing\n * hyphen turned \"show me what would go out\" into \"send it now.\" Fail closed.\n *\n * The map lives in ONE file rather than being colocated on each CommandSpec so\n * the whole authorized surface is reviewable at a glance, and so a single test\n * can assert that every registered command has an entry (flagSpec.test.ts).\n * A command with no flags of its own must still be listed, with an empty array\n * — absence is a bug, not \"allow everything\".\n */\n\nimport { UsageError } from './errors.js';\n\n/** Accepted on every command, so each entry below lists only its own flags. */\nexport const GLOBAL_FLAGS: readonly string[] = ['json', 'dry-run', 'help', 'h'];\n\n/** Shared by the four compose surfaces (send/reply-family/draft) via compose.ts. */\nconst COMPOSE_FLAGS: readonly string[] = [\n 'to',\n 'cc',\n 'bcc',\n 'subject',\n 'body',\n 'body-file',\n 'html',\n 'attach',\n 'signature',\n];\n\n/**\n * command name -> flags it accepts, beyond GLOBAL_FLAGS.\n *\n * Note on `--no-x`: the parser strips the `no-` prefix and records the bare\n * name, so `--no-save-sent` validates against `save-sent`. Only the bare name\n * belongs here.\n */\nexport const COMMAND_FLAGS: Readonly<Record<string, readonly string[]>> = {\n auth: ['readonly', 'scopes'],\n me: [],\n list: ['folder', 'limit', 'all', 'unread'],\n get: ['html'],\n search: ['limit', 'all', 'folder'],\n folders: ['parent', 'all', 'name'],\n attachments: ['all', 'out', 'force'],\n contacts: ['top', 'all', 'limit', 'select', 'filter'],\n send: [...COMPOSE_FLAGS, 'save-sent'],\n reply: ['body', 'signature'],\n 'reply-all': ['body', 'signature'],\n forward: ['body', 'to', 'signature'],\n draft: [...COMPOSE_FLAGS, 'limit', 'all'],\n move: ['folder'],\n delete: [],\n purge: ['yes'],\n 'mark-read': [],\n 'mark-unread': [],\n flag: [],\n unflag: [],\n rules: ['name', 'folder', 'from', 'sender-contains', 'mark-read', 'stop-processing', 'enabled', 'sequence'],\n};\n\n/** Levenshtein, capped — only used to build a \"did you mean\" hint. */\nfunction editDistance(a: string, b: string): number {\n const rows = a.length + 1;\n const cols = b.length + 1;\n let prev: number[] = Array.from({ length: cols }, (_, j) => j);\n\n for (let i = 1; i < rows; i++) {\n const curr: number[] = [i];\n for (let j = 1; j < cols; j++) {\n const substitution = (prev[j - 1] ?? 0) + (a[i - 1] === b[j - 1] ? 0 : 1);\n const insertion = (curr[j - 1] ?? 0) + 1;\n const deletion = (prev[j] ?? 0) + 1;\n curr[j] = Math.min(substitution, insertion, deletion);\n }\n prev = curr;\n }\n return prev[cols - 1] ?? Math.max(a.length, b.length);\n}\n\n/** Closest allowed flag within a small edit distance, for the error hint. */\nfunction suggest(unknown: string, allowed: readonly string[]): string | undefined {\n let best: string | undefined;\n let bestScore = Number.POSITIVE_INFINITY;\n\n for (const candidate of allowed) {\n const score = editDistance(unknown.toLowerCase(), candidate.toLowerCase());\n if (score < bestScore) {\n bestScore = score;\n best = candidate;\n }\n }\n\n // Distance 3 catches `dryrun` -> `dry-run` (1) and `subjekt` -> `subject` (1)\n // without proposing nonsense for a genuinely unrelated token.\n const ceiling = Math.min(3, Math.max(1, Math.floor(unknown.length / 2)));\n return best !== undefined && bestScore <= ceiling ? best : undefined;\n}\n\n/**\n * Throw if the invocation carries a flag the command does not define.\n *\n * @param commandName registered command name (used to look up the allowlist)\n * @param used every flag name the parser actually saw\n */\nexport function assertKnownFlags(commandName: string, used: readonly string[]): void {\n const own = COMMAND_FLAGS[commandName];\n if (own === undefined) {\n // An unregistered command reaching here means the registry and this map\n // drifted apart. Fail closed rather than silently allowing everything.\n throw new UsageError(\n `Internal: no flag specification registered for command '${commandName}'.`,\n );\n }\n\n const allowed = [...GLOBAL_FLAGS, ...own];\n const allowedSet = new Set(allowed);\n const unknown = used.filter((name) => !allowedSet.has(name));\n if (unknown.length === 0) return;\n\n const first = unknown[0] ?? '';\n const hint = suggest(first, allowed);\n const lines = [\n `Unknown flag for '${commandName}': --${unknown.map((u) => u).join(', --')}`,\n ];\n if (hint !== undefined) lines.push(`Did you mean --${hint}?`);\n lines.push(\n '',\n `Accepted: ${allowed.map((f) => `--${f}`).join(' ')}`,\n `Run 'outlook ${commandName} --help' for usage.`,\n );\n\n throw new UsageError(lines.join('\\n'));\n}\n","/**\n * Secret scrubbing. Every path that prints — logs, errors, --dry-run output,\n * `auth status` — routes through here. Nothing else is trusted to remember.\n */\n\n/** Keys whose values are always secret, regardless of shape. */\nconst SECRET_KEYS = new Set([\n 'access_token',\n 'refresh_token',\n 'id_token',\n 'device_code',\n 'client_secret',\n 'accesstoken',\n 'refreshtoken',\n 'authorization',\n 'code_verifier',\n]);\n\n/** JWTs and long opaque bearer blobs. */\nconst JWT_RE = /\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g;\nconst BEARER_RE = /\\b(Bearer\\s+)[A-Za-z0-9._~+/-]{20,}=*/gi;\n/** Microsoft refresh tokens: long base64url-ish runs, often prefixed 0.A / M.C / 1.A */\nconst OPAQUE_TOKEN_RE = /\\b[0-9A-Za-z]\\.[A-Za-z0-9_-]{40,}/g;\n\nexport const MASK = '[REDACTED]';\n\n/** Mask a known-secret string, keeping a short tail for correlation. */\nexport function maskSecret(value: string): string {\n if (!value) return MASK;\n if (value.length <= 8) return MASK;\n return `${MASK}(****${value.slice(-4)})`;\n}\n\n/** Scrub secrets out of free text (error bodies, HTTP traces). */\nexport function redactText(text: string): string {\n if (!text) return text;\n return text\n .replace(JWT_RE, MASK)\n .replace(BEARER_RE, (_m, p1: string) => `${p1}${MASK}`)\n .replace(OPAQUE_TOKEN_RE, MASK);\n}\n\n/**\n * Deep-clone a value with every secret-keyed field masked.\n * Used before any JSON.stringify that could reach a terminal or log.\n */\nexport function redactObject<T>(input: T): T {\n return walk(input, 0) as T;\n}\n\nfunction walk(value: unknown, depth: number): unknown {\n // Past the cap this must mask, not pass through: returning `value` here let\n // a secret nested one level deeper than the cap print raw, defeating the\n // one guarantee this module exists to make.\n if (depth > 12) return MASK;\n\n if (typeof value === 'string') return redactText(value);\n if (value === null || typeof value !== 'object') return value;\n\n if (Array.isArray(value)) {\n return value.map((item) => walk(item, depth + 1));\n }\n\n const out: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n if (SECRET_KEYS.has(key.toLowerCase())) {\n out[key] = typeof val === 'string' ? maskSecret(val) : MASK;\n } else {\n out[key] = walk(val, depth + 1);\n }\n }\n return out;\n}\n\n/** Redact an outbound header map for --dry-run display. */\nexport function redactHeaders(\n headers: Record<string, string>,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, val] of Object.entries(headers)) {\n out[key] = SECRET_KEYS.has(key.toLowerCase()) ? MASK : redactText(val);\n }\n return out;\n}\n","/**\n * Local token cache: a single JSON file, chmod 0600. A corrupt or unreadable\n * cache must never crash the CLI — it just means \"sign in again,\" so `load`\n * swallows every failure mode (missing file, bad JSON, wrong shape) and\n * returns `null` rather than throwing.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { isScopeArray } from './scopes.js';\nimport type { TokenSet } from './types.js';\n\n/** Owner read/write only — the file holds an access + refresh token. */\nconst FILE_MODE = 0o600;\n\n/**\n * Owner-only on the containing directory too. The file itself is already 0600,\n * so this is not what protects the secret — it stops a world-readable directory\n * from advertising that a token cache exists and when it was last written.\n */\nconst DIR_MODE = 0o700;\n\n/**\n * chmod cannot express \"owner only\" through the Win32 ACL model, so on Windows\n * the 0600 above is decorative and the token file inherits directory\n * permissions. Callers are told once, loudly, rather than being left with a\n * false sense of protection. See docs/security-review-2026-08-07.md (#4).\n */\nexport const FILE_MODE_IS_ENFORCED = process.platform !== 'win32';\n\nexport interface TokenStore {\n readonly path: string;\n load(): Promise<TokenSet | null>;\n save(tokens: TokenSet): Promise<void>;\n clear(): Promise<void>;\n}\n\nexport function createTokenStore(path: string): TokenStore {\n return {\n path,\n\n async load(): Promise<TokenSet | null> {\n try {\n const raw = await readFile(path, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n return isTokenSet(parsed) ? parsed : null;\n } catch {\n // ENOENT, EACCES, malformed JSON, a directory where a file should\n // be — all of it collapses to \"no usable cache.\" Never throw.\n return null;\n }\n },\n\n /**\n * Atomic: write a fresh temp file, lock it down, then rename over the\n * target. rename(2) is atomic within a directory, so a reader either sees\n * the whole old token set or the whole new one — never a half-written\n * file. The previous in-place writeFile could leave a truncated cache\n * behind if the process died mid-write, or interleave two concurrent\n * refreshes into corrupt JSON, either of which forces a re-login.\n *\n * The temp file carries the restrictive mode from creation, so the secret\n * is never briefly world-readable in the window before chmod lands.\n *\n * The temp NAME is random and the open is exclusive. The previous\n * `.${pid}-${Date.now()}.token.tmp` was guessable, and writeFile's default\n * O_CREAT|O_TRUNC follows a symlink — so a link pre-planted at that path\n * would have received the token at whatever destination it pointed to.\n * 'wx' (O_CREAT|O_EXCL) refuses to open anything that already exists.\n */\n async save(tokens: TokenSet): Promise<void> {\n const dir = dirname(path);\n await mkdir(dir, { recursive: true, mode: DIR_MODE });\n\n const tmp = join(dir, `.${randomBytes(8).toString('hex')}.token.tmp`);\n try {\n await writeFile(tmp, JSON.stringify(tokens, null, 2), {\n mode: FILE_MODE,\n flag: 'wx',\n });\n // `mode` on writeFile only applies at creation; chmod makes it\n // explicit. On Windows both are advisory — see FILE_MODE_IS_ENFORCED.\n await chmod(tmp, FILE_MODE);\n await rename(tmp, path);\n } catch (error) {\n // EEXIST means the path was already occupied by something this\n // function did not create. Removing it would be deleting a stranger's\n // file on the way out of a failure — leave it alone.\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {\n await rm(tmp, { force: true }).catch(() => undefined);\n }\n throw error;\n }\n },\n\n async clear(): Promise<void> {\n // force: true swallows ENOENT — clearing an already-absent cache is a\n // no-op, not an error.\n await rm(path, { force: true });\n },\n };\n}\n\n/** Runtime shape guard — a corrupt cache must degrade to `null`, not a crash. */\nfunction isTokenSet(value: unknown): value is TokenSet {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n\n if (typeof v['accessToken'] !== 'string' || v['accessToken'].length === 0) return false;\n if (typeof v['expiresAt'] !== 'number' || !Number.isFinite(v['expiresAt'])) return false;\n\n if (v['refreshToken'] !== undefined && typeof v['refreshToken'] !== 'string') return false;\n if (v['scope'] !== undefined && typeof v['scope'] !== 'string') return false;\n if (v['tokenType'] !== undefined && typeof v['tokenType'] !== 'string') return false;\n if (v['account'] !== undefined && typeof v['account'] !== 'string') return false;\n // An unrecognized mode must not silently read as 'full' (that would be a\n // privilege upgrade on a corrupt cache) — reject the whole cache instead.\n if (v['mode'] !== undefined && v['mode'] !== 'readonly' && v['mode'] !== 'full') {\n return false;\n }\n // Same reasoning: a malformed custom scope set must not fall back to the\n // default (wider) scopes on the next refresh.\n if (v['grantScopes'] !== undefined && !isScopeArray(v['grantScopes'])) return false;\n\n return true;\n}\n","/**\n * Parsing for `outlook auth login --scopes <comma list>`.\n *\n * A custom scope set lets one job (an unattended mail-moving agent, say) hold\n * a token that is narrower than the default grant, e.g. only `Mail.ReadWrite`.\n * The exact set requested is persisted with the token (`grantScopes`) so that\n * `auth refresh` asks Azure for the SAME set again instead of DEFAULT_SCOPES —\n * otherwise the first refresh would quietly widen the grant back to the full\n * scope list.\n */\n\nimport { UsageError } from './errors.js';\n\n/** Graph scope tokens: `Mail.ReadWrite`, `offline_access`, or a full resource URI. */\nconst SCOPE_RE = /^[A-Za-z0-9._:/-]+$/;\n\nconst OFFLINE_ACCESS = 'offline_access';\n\n/**\n * Split a comma (or whitespace) separated scope list, validate each token,\n * drop case-insensitive duplicates, and make sure `offline_access` is present\n * — without it Azure issues no refresh token and the session dies in an hour.\n */\nexport function parseScopeList(raw: string): string[] {\n const tokens = raw\n .split(/[\\s,]+/)\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n\n if (tokens.length === 0) {\n throw new UsageError('--scopes needs at least one scope, e.g. --scopes Mail.ReadWrite');\n }\n\n const seen = new Set<string>();\n const scopes: string[] = [];\n for (const token of tokens) {\n if (!SCOPE_RE.test(token)) {\n throw new UsageError(`--scopes: \"${token}\" is not a valid scope name.`);\n }\n const key = token.toLowerCase();\n if (seen.has(key)) continue;\n seen.add(key);\n scopes.push(token);\n }\n\n if (!seen.has(OFFLINE_ACCESS)) scopes.unshift(OFFLINE_ACCESS);\n return scopes;\n}\n\n/** Runtime guard for the persisted `grantScopes` field. */\nexport function isScopeArray(value: unknown): value is string[] {\n return (\n Array.isArray(value) &&\n value.length > 0 &&\n value.every((s) => typeof s === 'string' && SCOPE_RE.test(s))\n );\n}\n","/**\n * `outlook attachments` — list and download message attachments\n * (docs/01-read-endpoints.md §7).\n *\n * Both subcommands only ever GET from Graph — `list` renders metadata,\n * `download` writes bytes to LOCAL disk. It was previously `mutating: false`\n * on the reasoning that local writes are not mutations of remote mailbox\n * state; that is true of the MAILBOX but wrong from where the caller sits,\n * because `--dry-run` still created real files. `--dry-run` means \"cause no\n * side effects,\" so this command is `mutating: true` and `downloadHandler`\n * honors the flag directly (guardMutation wraps a Graph RequestSpec, which is\n * not what the write here is).\n *\n * Only one Graph endpoint is used, for both subcommands:\n * GET /me/messages/{id}/attachments (docs/01 §7.1)\n * docs/01 §7.3's own example response embeds `contentBytes` directly in the\n * list payload (no `$expand` needed), and §7.1 additionally documents that\n * `$filter` on `/attachments` is silently ignored — \"filter client-side after\n * listing\" is the docs' own guidance (§7.1). So `download <id> [attachmentId]`\n * does not invent a separate single-attachment GET path; it fetches the same\n * list `collectItems` fetches for `list` and selects client-side. Pagination\n * is always fully collected (`{ all: true }`) since docs/01 documents no\n * `$top` ceiling for this collection (§9, open question 3) — a partial page\n * would silently under-list or under-download attachments.\n *\n * Subcommand dispatch on `positionals[0]`, but unlike folders.ts's `list`\n * (which takes no id of its own), `attachments list` DOES consume a\n * positional (`<messageId>`) — so an unrecognized first token can't be\n * treated as an invalid-subcommand error the way folders.ts does; it must\n * be treated as the id itself under the default `list` behavior. Only the\n * two known keywords shift the id one slot to the right:\n * `download ...` -> download subcommand, id at positionals[1]\n * `list <messageId>` -> list subcommand, id at positionals[1]\n * anything else / absent -> list subcommand, id at positionals[0]\n * (Graph message ids are opaque generated strings and never collide with\n * the literal keywords \"list\"/\"download\" in practice.)\n */\n\nimport { access, mkdir, writeFile } from 'node:fs/promises';\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport { emit, type CommandContext, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport { renderAttachments } from '../output.js';\nimport { collectItems } from '../paginate.js';\nimport { sanitizeFilename } from '../safeFilename.js';\nimport type { Attachment } from '../types.js';\n\n/**\n * Metadata view of an attachment, with `contentBytes` removed.\n *\n * `attachments list --json` used to emit the raw Graph objects, and docs/01\n * §7.3 embeds the FULL base64 payload in the list response — so listing a\n * message dumped every attachment's complete contents into stdout, and from\n * there into whatever log an agent driving this CLI keeps. The human renderer\n * never showed those bytes; the JSON path now matches it.\n */\nfunction withoutContent(a: Attachment): Omit<Attachment, 'contentBytes'> {\n const { contentBytes: _omitted, ...rest } = a;\n return rest;\n}\n\nconst FILE_TYPE = 'microsoft.graph.fileAttachment';\n\n/** Strips an optional leading '#' (docs/01 §7.3: S9's own example omits it). */\nfunction normalizedType(a: Attachment): string {\n return (a['@odata.type'] ?? '').replace(/^#/, '');\n}\n\nfunction isFileAttachment(a: Attachment): boolean {\n return normalizedType(a) === FILE_TYPE;\n}\n\n/** Human label for error messages. output.ts's equivalent `attachmentKind`\n * helper is not exported, so this is a small, deliberately local duplicate. */\nfunction kindLabel(a: Attachment): string {\n const t = normalizedType(a);\n return t.startsWith('microsoft.graph.') ? t.slice('microsoft.graph.'.length) : t || 'unknown';\n}\n\nasync function fetchAttachments(ctx: CommandContext, messageId: string): Promise<Attachment[]> {\n const path = `/me/messages/${encodeURIComponent(messageId)}/attachments`;\n return collectItems<Attachment>(ctx.client, path, { all: true });\n}\n\nasync function listHandler(ctx: CommandContext, idIndex: number): Promise<void> {\n const messageId = ctx.args.requirePositional(idIndex, '<messageId>');\n const attachments = await fetchAttachments(ctx, messageId);\n emit(ctx, attachments.map(withoutContent), () => renderAttachments(attachments));\n}\n\n/**\n * Basenames the server-supplied name (strips any `../` or absolute prefix)\n * and then double-checks the resolved path is still inside `outDir` — the\n * two required layers of the path-traversal guard (docs' `name` is\n * attacker-controlled server data, not to be trusted for local disk writes).\n */\nfunction safeDestination(outDir: string, attachment: Attachment): string {\n const fallback = `attachment-${attachment.id}`;\n const raw = attachment.name && attachment.name.trim() ? attachment.name : fallback;\n // basename() first (strips any directory part, POSIX or Win32), then the\n // cross-platform character/reserved-name pass — see safeFilename.ts.\n const base = basename(raw.replace(/\\\\/g, '/'));\n const name = sanitizeFilename(base, fallback);\n const dest = resolve(outDir, name);\n const rel = relative(outDir, dest);\n // `rel.startsWith('..')` alone also rejects a legitimate `..gitignore`,\n // whose relative path merely begins with those two characters. Escape means\n // the whole first segment is `..`, so match the separator too.\n if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {\n throw new UsageError(`Refusing to write outside --out directory: \"${attachment.name}\"`);\n }\n return dest;\n}\n\n/**\n * Allocate one destination per attachment, in order, with no two alike.\n *\n * `sanitizeFilename` is deliberately many-to-one — `a:b.txt` and `a?b.txt`\n * both land on `a_b.txt` — and Outlook routinely puts two attachments named\n * `image001.png` on a single message. Resolving each attachment independently\n * therefore aimed two downloads at one path: with --force the second write\n * clobbered the first while the results array still reported both as written\n * to their own file, and without it the batch aborted halfway through.\n *\n * Allocating here, once, is also what keeps --dry-run honest: the plan and the\n * real run consume the same allocator, so they cannot disagree about where a\n * file lands.\n */\nfunction allocateDestinations(outDir: string, attachments: readonly Attachment[]): string[] {\n const claimed = new Set<string>();\n return attachments.map((attachment) => claim(safeDestination(outDir, attachment), claimed));\n}\n\nfunction claim(dest: string, claimed: Set<string>): string {\n // macOS and Windows treat `A.txt` and `a.txt` as one file, so uniqueness has\n // to be decided case-insensitively or the collision survives on those hosts.\n const key = (p: string): string => p.toLowerCase();\n if (!claimed.has(key(dest))) {\n claimed.add(key(dest));\n return dest;\n }\n\n const dir = dirname(dest);\n const base = basename(dest);\n const dot = base.lastIndexOf('.');\n // `dot > 0` keeps a dotfile whole: `.gitignore` is all stem, no extension.\n const stem = dot > 0 ? base.slice(0, dot) : base;\n const ext = dot > 0 ? base.slice(dot) : '';\n\n for (let n = 2; ; n++) {\n const candidate = join(dir, `${stem} (${n})${ext}`);\n if (!claimed.has(key(candidate))) {\n claimed.add(key(candidate));\n return candidate;\n }\n }\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n}\n\ninterface DownloadResult {\n id: string;\n name: string;\n path: string;\n size: number;\n}\n\nasync function downloadOne(dest: string, attachment: Attachment, force: boolean): Promise<DownloadResult> {\n if (!isFileAttachment(attachment)) {\n throw new UsageError(\n `Cannot download \"${attachment.name}\" — ${kindLabel(attachment)} has no downloadable bytes (docs/01 §7.4)`,\n );\n }\n if (!force && (await exists(dest))) {\n throw new UsageError(`Refusing to overwrite existing file: ${dest} (pass --force)`);\n }\n const buf = Buffer.from(attachment.contentBytes ?? '', 'base64');\n await writeFile(dest, buf);\n return { id: attachment.id, name: attachment.name, path: dest, size: buf.length };\n}\n\nasync function downloadHandler(ctx: CommandContext): Promise<void> {\n const messageId = ctx.args.requirePositional(1, '<messageId>');\n const attachmentId = ctx.args.positionals[2];\n const all = ctx.args.bool('all');\n const force = ctx.args.bool('force');\n const outDir = resolve(ctx.args.str('out', process.cwd()) ?? process.cwd());\n\n if (!all && !attachmentId) {\n throw new UsageError('outlook attachments download requires [attachmentId] or --all');\n }\n\n const attachments = await fetchAttachments(ctx, messageId);\n const targets = all ? attachments : attachments.filter((a) => a.id === attachmentId);\n if (!all && targets.length === 0) {\n throw new UsageError(`No attachment with id \"${attachmentId}\" on message ${messageId}`);\n }\n\n // `download` writes bytes to local disk, which is a side effect a caller\n // passing --dry-run has explicitly asked not to happen. guardMutation is\n // the wrong tool (it wraps a *Graph* RequestSpec, and the only Graph call\n // here is the read that got us `targets`), so the check is explicit — but\n // it must still come BEFORE mkdir, or a dry run leaves a directory behind.\n // One allocation shared by both branches below, so the dry-run plan names\n // exactly the paths a real run would write.\n const destinations = allocateDestinations(outDir, targets);\n\n if (ctx.dryRun) {\n const planned = targets.map((a, i) => ({\n id: a.id,\n name: a.name,\n path: destinations[i] as string,\n }));\n emit(ctx, { dryRun: true, wouldWrite: planned }, () =>\n [\n 'DRY RUN — nothing was written. These files would be created:',\n '',\n ...(planned.length === 0\n ? ['(nothing to download)']\n : planned.map((p) => ` ${p.path}`)),\n ].join('\\n'),\n );\n return;\n }\n\n await mkdir(outDir, { recursive: true });\n\n const results: DownloadResult[] = [];\n for (const [i, attachment] of targets.entries()) {\n results.push(await downloadOne(destinations[i] as string, attachment, force));\n }\n\n emit(ctx, results, () =>\n results.length === 0\n ? '(nothing to download)'\n : results.map((r) => `${r.name} -> ${r.path} (${r.size} bytes)`).join('\\n'),\n );\n}\n\nasync function attachmentsHandler(ctx: CommandContext): Promise<void> {\n const sub = ctx.args.positionals[0];\n if (sub === 'download') return downloadHandler(ctx);\n if (sub === 'list') return listHandler(ctx, 1);\n return listHandler(ctx, 0); // no keyword: sub, if present, IS the messageId\n}\n\nexport const attachmentsCommand: CommandSpec = {\n name: 'attachments',\n summary: 'List or download the attachments on a message',\n usage:\n 'outlook attachments [list|download] <messageId> [attachmentId] [--all] [--out dir] [--force] [--dry-run] [--json]',\n mutating: true,\n handler: attachmentsHandler,\n};\n","/**\n * Human-readable, copy-pasteable rendering of a RequestSpec for `--dry-run`.\n * Must never require a token or touch the network — RequestSpec is already\n * fully materialized by GraphClient#buildSpec by the time this runs.\n */\n\nimport { redactHeaders, redactObject } from './redact.js';\nimport type { RequestSpec } from './types.js';\n\nexport function renderRequest(spec: RequestSpec): string {\n const lines: string[] = [];\n\n lines.push(`${spec.method} ${spec.url}`);\n\n const headers = redactHeaders(spec.headers ?? {});\n for (const [key, value] of Object.entries(headers)) {\n lines.push(`${key}: ${value}`);\n }\n\n if (spec.body !== undefined) {\n lines.push('');\n lines.push(JSON.stringify(redactObject(spec.body), null, 2));\n }\n\n return lines.join('\\n');\n}\n","/**\n * Enforcement of the OUTLOOK_POLICY mutation policy (policy.ts).\n *\n * Called only from guardMutation (command.ts), the chokepoint every\n * state-changing Graph request already passes through, so no command can skip\n * it. With OUTLOOK_POLICY unset every function here is a no-op and behavior is\n * exactly as before.\n *\n * This is a guard INSIDE the CLI, not an operating-system boundary: a process\n * that can run arbitrary code as the same user can read the token cache and\n * call Graph directly. Its job is to keep an agent that drives the CLI inside\n * the lines it was given, and to fail closed when the policy cannot be read.\n */\n\nimport { dirname, resolve } from 'node:path';\nimport type { CommandContext } from './command.js';\nimport { PolicyRefusedError } from './errors.js';\nimport { POLICY_ENV, loadDenyList, loadPolicy, sameFolder, type MutationPolicy } from './policy.js';\nimport type { RequestSpec } from './types.js';\n\nexport interface PolicyVerdict {\n policyPath: string;\n allowed: boolean;\n /** Which clause refused: policy-file, allowCommands, request-path, move.allowedDestinations, move.denySenders. */\n rule?: string;\n reason?: string;\n /** Deny-list status for a move into a protected destination. */\n senderCheck?: 'passed' | 'skipped-dry-run';\n}\n\nexport interface PolicyInput {\n env: Readonly<Record<string, string | undefined>> | undefined;\n /** Registered command name, e.g. \"move\" or \"draft\". */\n command: string | undefined;\n /** positionals[0] — the subcommand for draft/folders/rules. */\n subcommand: string | undefined;\n spec: RequestSpec;\n dryRun: boolean;\n /** GET the message's sender address. Never called under dry-run. */\n lookupSender: (messageId: string) => Promise<string | undefined>;\n now?: () => number;\n}\n\nexport function policyPath(\n env: Readonly<Record<string, string | undefined>> | undefined,\n): string | undefined {\n const value = env?.[POLICY_ENV]?.trim();\n return value ? value : undefined;\n}\n\nfunction normalizeCommand(name: string): string {\n return name.trim().toLowerCase().replace(/\\s+/g, ' ');\n}\n\n/** \"draft create\" is allowed by an entry of either \"draft create\" or \"draft\". */\nfunction commandAllowed(policy: MutationPolicy, command: string, sub: string | undefined): boolean {\n const allowed = new Set(policy.allowCommands.map(normalizeCommand));\n const base = normalizeCommand(command);\n if (allowed.has(base)) return true;\n return sub !== undefined && allowed.has(normalizeCommand(`${base} ${sub}`));\n}\n\n/** Path part of the request URL, before any query string, without normalization. */\nfunction rawPath(url: string): string {\n return url.replace(/^https?:\\/\\/[^/]*/i, '').split(/[?#]/)[0] ?? '';\n}\n\n/**\n * Message ids go into request paths unescaped, so an id such as\n * `../mailFolders/inbox` would turn \"move one message\" into \"move a whole\n * folder\" once the URL is normalized. Under a policy, refuse any path the\n * URL parser would rewrite.\n */\nfunction unsafePathReason(url: string): string | undefined {\n for (const segment of rawPath(url).split('/')) {\n let decoded: string;\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n return 'request path contains a malformed percent-encoding';\n }\n if (decoded === '.' || decoded === '..' || decoded.includes('\\\\') || decoded.includes('/')) {\n return 'request path contains a dot segment, backslash or encoded slash';\n }\n // Defense-in-depth: a legitimately constructed message id never contains\n // a bare '%' after one decode — a remaining '%' means double-encoding.\n if (decoded.includes('%')) {\n return 'request path contains a double-encoded percent sequence';\n }\n }\n return undefined;\n}\n\ninterface MoveTarget {\n destination: string;\n messageId: string | undefined;\n}\n\n/**\n * Map a purge (DELETE /me/messages/{id}) to a logical destination of\n * \"deleteditems\" so move.allowedDestinations and move.denySenders apply.\n */\nfunction purgeTarget(spec: RequestSpec): MoveTarget | undefined {\n if (spec.method.toUpperCase() !== 'DELETE') return undefined;\n const path = rawPath(spec.url);\n // Match /me/messages/{id} with no trailing path segment (not a sub-resource).\n const match = /\\/me\\/messages\\/([^/]+)$/.exec(path);\n if (!match) return undefined;\n return { destination: 'deleteditems', messageId: match[1] };\n}\n\n/** A POST ending in /move (message or folder move); undefined for anything else. */\nfunction moveTarget(spec: RequestSpec): MoveTarget | undefined {\n if (spec.method.toUpperCase() !== 'POST') return undefined;\n const path = rawPath(spec.url);\n if (!path.endsWith('/move')) return undefined;\n const body = spec.body as { destinationId?: unknown } | undefined;\n const destination = typeof body?.destinationId === 'string' ? body.destinationId : '';\n const match = /\\/me\\/messages\\/([^/]+)\\/move$/.exec(path);\n return { destination, messageId: match?.[1] };\n}\n\n/** Undefined when no policy is configured; otherwise the verdict for this request. */\nexport async function evaluatePolicy(input: PolicyInput): Promise<PolicyVerdict | undefined> {\n const path = policyPath(input.env);\n if (path === undefined) return undefined;\n const refuse = (rule: string, reason: string): PolicyVerdict => ({\n policyPath: path,\n allowed: false,\n rule,\n reason,\n });\n\n const loaded = await loadPolicy(path);\n if (!loaded.ok) return refuse('policy-file', loaded.reason);\n const policy = loaded.value;\n\n if (input.command === undefined) {\n return refuse('allowCommands', 'cannot determine which command issued this request');\n }\n if (!commandAllowed(policy, input.command, input.subcommand)) {\n const label = input.subcommand ? `${input.command} ${input.subcommand}` : input.command;\n return refuse('allowCommands', `'${label}' is not in allowCommands`);\n }\n\n const pathProblem = unsafePathReason(input.spec.url);\n if (pathProblem !== undefined) return refuse('request-path', pathProblem);\n\n const move = moveTarget(input.spec) ?? purgeTarget(input.spec);\n if (move === undefined) return { policyPath: path, allowed: true };\n const { destination, messageId } = move;\n if (destination === '') return refuse('purge', 'purge request could not determine destination');\n\n const allowedDestinations = policy.move?.allowedDestinations;\n if (allowedDestinations !== undefined && !allowedDestinations.some((d) => sameFolder(d, destination))) {\n return refuse(\n 'move.allowedDestinations',\n `destination '${destination}' is not in move.allowedDestinations`,\n );\n }\n\n const deny = policy.move?.denySenders;\n if (deny === undefined || !deny.destinations.some((d) => sameFolder(d, destination))) {\n return { policyPath: path, allowed: true };\n }\n\n const now = input.now ?? Date.now;\n const listFile = resolve(dirname(path), deny.file);\n const list = await loadDenyList(listFile, deny.maxAgeHours, now());\n if (!list.ok) return refuse('move.denySenders', `${list.reason}; moves to '${destination}' are refused`);\n if (messageId === undefined) {\n return refuse('move.denySenders', 'cannot identify the message, so its sender cannot be checked');\n }\n if (input.dryRun) return { policyPath: path, allowed: true, senderCheck: 'skipped-dry-run' };\n\n // Errors (auth, 404, throttling) propagate: the move does not happen.\n const sender = (await input.lookupSender(messageId))?.trim().toLowerCase();\n if (!sender) return refuse('move.denySenders', 'the message has no sender address to check');\n if (list.value.has(sender)) {\n return refuse('move.denySenders', `sender ${sender} is on the deny list for '${destination}'`);\n }\n return { policyPath: path, allowed: true, senderCheck: 'passed' };\n}\n\nasync function verdictFor(ctx: CommandContext, spec: RequestSpec): Promise<PolicyVerdict | undefined> {\n return evaluatePolicy({\n env: ctx.env,\n command: ctx.command,\n subcommand: ctx.args.positionals[0],\n spec,\n dryRun: ctx.dryRun,\n lookupSender: async (messageId) => {\n const message = await ctx.client.get<{ from?: { emailAddress?: { address?: string } } }>(\n `/me/messages/${messageId}`,\n { $select: 'from' },\n );\n return message?.from?.emailAddress?.address;\n },\n });\n}\n\n/** Throws PolicyRefusedError (exit 4) when a configured policy refuses the request. */\nexport async function enforcePolicy(ctx: CommandContext, spec: RequestSpec): Promise<void> {\n const verdict = await verdictFor(ctx, spec);\n if (verdict === undefined || verdict.allowed) return;\n const rule = verdict.rule ?? 'policy';\n const reason = verdict.reason ?? 'refused';\n if (ctx.json) {\n ctx.out(\n JSON.stringify(\n { error: { code: 'PolicyRefused', rule, message: reason, policy: verdict.policyPath } },\n null,\n 2,\n ),\n );\n }\n throw new PolicyRefusedError(rule, reason);\n}\n\n/** For --dry-run: the verdict without any network call (undefined when no policy is set). */\nexport async function dryRunVerdict(\n ctx: CommandContext,\n spec: RequestSpec,\n): Promise<PolicyVerdict | undefined> {\n return verdictFor({ ...ctx, dryRun: true }, spec);\n}\n\nexport function renderVerdict(verdict: PolicyVerdict): string {\n const head = `Policy (${verdict.policyPath}):`;\n if (!verdict.allowed) return `${head} would REFUSE (${verdict.rule}): ${verdict.reason}`;\n if (verdict.senderCheck === 'skipped-dry-run') {\n return (\n `${head} would ALLOW unless the message's sender is on the deny list ` +\n `(the sender lookup is a network call, so --dry-run skipped it).`\n );\n }\n return `${head} would ALLOW this request.`;\n}\n","/**\n * The OUTLOOK_POLICY file: loading and validation.\n *\n * A policy confines what an unattended caller may change in the mailbox. It is\n * read fresh on every guarded mutation and NEVER consulted for reads. Every\n * failure here is reported as `{ ok: false, reason }` rather than thrown,\n * because the caller's answer to any of them is the same: refuse (fail closed).\n * A policy that cannot be read is not \"no policy\".\n *\n * Example:\n * {\n * \"allowCommands\": [\"move\", \"mark-read\"],\n * \"move\": {\n * \"allowedDestinations\": [\"<review-folder-id>\", \"archive\"],\n * \"denySenders\": {\n * \"file\": \"protected_senders.json\",\n * \"maxAgeHours\": 48,\n * \"destinations\": [\"<review-folder-id>\"]\n * }\n * }\n * }\n */\n\nimport { readFile, stat } from 'node:fs/promises';\nimport { isWellKnownFolder } from './types.js';\n\nexport const POLICY_ENV = 'OUTLOOK_POLICY';\n\nexport interface DenySendersRule {\n /** JSON file: an array of addresses, or `{ addresses: [...], built_at: ISO }`. Relative to the policy file. */\n file: string;\n /** Older than this (by built_at, else file mtime) and the list is not trusted. */\n maxAgeHours: number;\n /** Moves INTO these folders are checked against the list. */\n destinations: string[];\n}\n\nexport interface MutationPolicy {\n /** Command names allowed to mutate, e.g. \"move\", \"draft create\". A bare \"draft\" allows every draft subcommand. */\n allowCommands: string[];\n move?: {\n allowedDestinations?: string[];\n denySenders?: DenySendersRule;\n };\n}\n\nexport type Loaded<T> = { ok: true; value: T } | { ok: false; reason: string };\n\nconst TOP_KEYS = new Set(['allowCommands', 'move']);\nconst MOVE_KEYS = new Set(['allowedDestinations', 'denySenders']);\nconst DENY_KEYS = new Set(['file', 'maxAgeHours', 'destinations']);\n\n/** A UTF-8 BOM (common in files written by Windows tools) is not JSON. */\nfunction stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\nfunction isStringList(v: unknown, allowEmpty: boolean): v is string[] {\n return (\n Array.isArray(v) &&\n (allowEmpty || v.length > 0) &&\n v.every((s) => typeof s === 'string' && s.trim().length > 0)\n );\n}\n\n/**\n * Unknown keys are rejected (keys starting with `$`, e.g. `$comment`, are\n * allowed). A typo such as `allowedDestination` must not silently mean\n * \"no destination restriction\".\n */\nfunction unknownKey(obj: Record<string, unknown>, known: Set<string>): string | undefined {\n return Object.keys(obj).find((k) => !known.has(k) && !k.startsWith('$'));\n}\n\n/** Returns a description of the first problem, or undefined when valid. */\nexport function validatePolicy(v: unknown): string | undefined {\n if (!isRecord(v)) return 'top level must be a JSON object';\n const extra = unknownKey(v, TOP_KEYS);\n if (extra !== undefined) return `unknown key \"${extra}\"`;\n if (!isStringList(v['allowCommands'], true)) {\n return '\"allowCommands\" must be an array of command names (it may be empty)';\n }\n\n const move = v['move'];\n if (move === undefined) return undefined;\n if (!isRecord(move)) return '\"move\" must be an object';\n const extraMove = unknownKey(move, MOVE_KEYS);\n if (extraMove !== undefined) return `unknown key \"move.${extraMove}\"`;\n\n const allowed = move['allowedDestinations'];\n if (allowed !== undefined && !isStringList(allowed, true)) {\n return '\"move.allowedDestinations\" must be an array of folder ids or well-known names';\n }\n\n const deny = move['denySenders'];\n if (deny === undefined) return undefined;\n if (!isRecord(deny)) return '\"move.denySenders\" must be an object';\n const extraDeny = unknownKey(deny, DENY_KEYS);\n if (extraDeny !== undefined) return `unknown key \"move.denySenders.${extraDeny}\"`;\n if (typeof deny['file'] !== 'string' || deny['file'].trim() === '') {\n return '\"move.denySenders.file\" must be a path';\n }\n const denyFile = deny['file'] as string;\n if (\n denyFile.startsWith('/') ||\n denyFile.includes('\\\\') ||\n denyFile.split('/').some((seg) => seg === '..')\n ) {\n return '\"move.denySenders.file\" must be a relative path with no \\'..\\' segments or backslashes';\n }\n const maxAge = deny['maxAgeHours'];\n if (typeof maxAge !== 'number' || !Number.isFinite(maxAge) || maxAge <= 0) {\n return '\"move.denySenders.maxAgeHours\" must be a positive number';\n }\n if (!isStringList(deny['destinations'], false)) {\n return '\"move.denySenders.destinations\" must be a non-empty array of folder ids';\n }\n return undefined;\n}\n\nexport async function loadPolicy(path: string): Promise<Loaded<MutationPolicy>> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf8');\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code ?? 'read error';\n return { ok: false, reason: `cannot read policy file ${path} (${code})` };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(stripBom(raw));\n } catch {\n return { ok: false, reason: `policy file ${path} is not valid JSON` };\n }\n\n const problem = validatePolicy(parsed);\n if (problem !== undefined) {\n return { ok: false, reason: `policy file ${path} is invalid: ${problem}` };\n }\n return { ok: true, value: parsed as MutationPolicy };\n}\n\n/**\n * Load the sender deny list. Missing, unparseable, wrongly shaped, or stale\n * all fail: a list that cannot be trusted to be current cannot vouch that a\n * sender is NOT on it.\n */\nexport async function loadDenyList(\n file: string,\n maxAgeHours: number,\n nowMs: number,\n): Promise<Loaded<Set<string>>> {\n let raw: string;\n try {\n raw = await readFile(file, 'utf8');\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code ?? 'read error';\n return { ok: false, reason: `cannot read deny list ${file} (${code})` };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(stripBom(raw));\n } catch {\n return { ok: false, reason: `deny list ${file} is not valid JSON` };\n }\n\n let addresses: unknown;\n let builtAt: unknown;\n if (Array.isArray(parsed)) {\n addresses = parsed;\n } else if (isRecord(parsed)) {\n addresses = parsed['addresses'];\n builtAt = parsed['built_at'];\n }\n if (!isStringList(addresses, true)) {\n return {\n ok: false,\n reason: `deny list ${file} must be an array of addresses or an object with an \"addresses\" array`,\n };\n }\n\n let stampMs: number;\n if (builtAt !== undefined) {\n stampMs = typeof builtAt === 'string' ? Date.parse(builtAt) : Number.NaN;\n if (Number.isNaN(stampMs)) {\n return { ok: false, reason: `deny list ${file} has an unparseable built_at` };\n }\n } else {\n try {\n stampMs = (await stat(file)).mtimeMs;\n } catch {\n return { ok: false, reason: `cannot stat deny list ${file}` };\n }\n }\n\n const ageHours = (nowMs - stampMs) / 3_600_000;\n if (ageHours > maxAgeHours) {\n return {\n ok: false,\n reason: `deny list ${file} is ${ageHours.toFixed(1)}h old (maxAgeHours ${maxAgeHours}); rebuild it`,\n };\n }\n\n return { ok: true, value: new Set(addresses.map((a) => a.trim().toLowerCase())) };\n}\n\n/**\n * Folder identity for policy matching: well-known names (`inbox`, `archive`)\n * compare case-insensitively, raw folder ids are opaque and compare exactly.\n * A well-known name and the id of that same folder do NOT match — list the\n * form the caller will actually pass.\n */\nexport function sameFolder(a: string, b: string): boolean {\n if (a === b) return true;\n return isWellKnownFolder(a) && isWellKnownFolder(b) && a.toLowerCase() === b.toLowerCase();\n}\n","/**\n * The contract every command binds to.\n *\n * The --dry-run short-circuit lives HERE, not in individual commands, so that\n * no command can forget it. Sending mail is irreversible and reaches real\n * people; `guardMutation` is the single chokepoint that makes the safe path\n * the default path.\n */\n\nimport type { ParsedArgs } from './args.js';\nimport type { Authenticator } from './auth.js';\nimport type { GraphClient } from './client.js';\nimport { renderRequest } from './dryRun.js';\nimport { InsufficientScopeError } from './errors.js';\nimport { dryRunVerdict, enforcePolicy, renderVerdict, type PolicyVerdict } from './policyGuard.js';\nimport { redactObject } from './redact.js';\nimport type { RequestSpec } from './types.js';\n\nexport interface CommandContext {\n args: ParsedArgs;\n /** --json: emit machine-readable output. */\n json: boolean;\n /** --dry-run: render the request, send nothing. */\n dryRun: boolean;\n /**\n * Registered command name (e.g. \"move\", \"draft\"), set by cli.ts. The\n * OUTLOOK_POLICY guard matches it against `allowCommands`; when a policy is\n * active and this is absent, every mutation is refused.\n */\n command?: string;\n client: GraphClient;\n auth: Authenticator;\n out: (line: string) => void;\n err: (line: string) => void;\n /**\n * Environment for per-invocation settings (e.g. signature files). Injected\n * rather than read from process.env so tests are hermetic; cli.ts passes\n * process.env. Absent means \"nothing configured\".\n */\n env?: Readonly<Record<string, string | undefined>>;\n}\n\nexport type CommandHandler = (ctx: CommandContext) => Promise<void>;\n\nexport interface CommandSpec {\n name: string;\n summary: string;\n usage: string;\n /** True when the command changes remote state — used to document --dry-run. */\n mutating: boolean;\n handler: CommandHandler;\n}\n\n/**\n * Wrap every state-changing Graph call. When --dry-run is set, prints the\n * exact request that WOULD have been issued and returns undefined without\n * touching the network. When OUTLOOK_POLICY is set, the dry run also reports\n * whether the policy would allow the request, and a real run is refused\n * (PolicyRefusedError, exit 4) unless the policy allows it.\n */\nexport async function guardMutation<T>(\n ctx: CommandContext,\n spec: RequestSpec,\n exec: () => Promise<T>,\n): Promise<T | undefined> {\n if (ctx.dryRun) {\n const verdict = await dryRunVerdict(ctx, spec);\n if (ctx.json) {\n ctx.out(\n JSON.stringify(\n {\n dryRun: true,\n request: redactSpecForJson(spec),\n ...(verdict === undefined ? {} : { policy: verdictJson(verdict) }),\n },\n null,\n 2,\n ),\n );\n } else {\n ctx.out('DRY RUN — nothing was sent. The request below is what would go out:');\n ctx.out('');\n ctx.out(renderRequest(spec));\n if (verdict !== undefined) {\n ctx.out('');\n ctx.out(renderVerdict(verdict));\n }\n }\n return undefined;\n }\n await assertWriteScope(ctx, spec);\n await enforcePolicy(ctx, spec);\n return exec();\n}\n\nfunction verdictJson(verdict: PolicyVerdict): Record<string, unknown> {\n return {\n path: verdict.policyPath,\n allowed: verdict.allowed,\n ...(verdict.rule === undefined ? {} : { rule: verdict.rule }),\n ...(verdict.reason === undefined ? {} : { reason: verdict.reason }),\n ...(verdict.senderCheck === undefined ? {} : { senderCheck: verdict.senderCheck }),\n };\n}\n\n/**\n * Refuse a mailbox-changing call when the cached grant was taken with\n * `--readonly`. Graph would reject it anyway, but only after the request has\n * left the machine and with a generic 403; catching it here keeps the failure\n * local, immediate, and phrased in terms of the flag the user actually chose.\n *\n * Lives on guardMutation for the same reason --dry-run does: it is the one\n * path every remote mutation already goes through, so no command can forget it.\n */\nasync function assertWriteScope(ctx: CommandContext, spec: RequestSpec): Promise<void> {\n const status = await ctx.auth.status();\n // Not signed in at all is NOT this error's business — let the token fetch\n // raise NotAuthenticatedError with its own instructions.\n if (!status.signedIn || status.mode !== 'readonly') return;\n throw new InsufficientScopeError(`${spec.method} ${spec.url}`);\n}\n\n/**\n * The JSON twin of dryRun.ts's `renderRequest`. Both paths print a request the\n * user is about to send, so both must scrub it identically — this one used to\n * pass `body` through untouched, which meant `--dry-run --json` leaked what\n * `--dry-run` alone had already masked. Headers are dropped entirely rather\n * than redacted: the Authorization header is attached later, inside the send\n * path, so it is not in the spec at all and printing the rest adds nothing.\n */\nfunction redactSpecForJson(spec: RequestSpec): RequestSpec {\n const { method, url, body } = spec;\n return {\n method,\n url,\n ...(body === undefined ? {} : { body: redactObject(body) }),\n };\n}\n\n/** Emit either JSON or a human rendering, chosen by --json. */\nexport function emit(\n ctx: CommandContext,\n data: unknown,\n human: () => string,\n): void {\n ctx.out(ctx.json ? JSON.stringify(data, null, 2) : human());\n}\n","/**\n * Attachment encoding + content-type sniffing + HTML-to-text conversion.\n * Inline attachment size rule sourced from docs/02-write-endpoints.md §6:\n * \"This operation limits the size of the attachment you can add to under 3 MB.\"\n */\n\nimport { readFile, stat } from 'node:fs/promises';\nimport { basename, extname } from 'node:path';\nimport { OutlookCliError } from './errors.js';\nimport type { FileAttachmentUpload } from './types.js';\n\n/** Inline-attachment ceiling per docs/02 §6 — \"under 3 MB.\" */\nexport const MAX_INLINE_ATTACHMENT_BYTES = 3 * 1024 * 1024;\n\nconst CONTENT_TYPES: Record<string, string> = {\n '.pdf': 'application/pdf',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.txt': 'text/plain',\n '.md': 'text/markdown',\n '.csv': 'text/csv',\n '.json': 'application/json',\n '.zip': 'application/zip',\n '.docx':\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.xlsx':\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.pptx':\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.html': 'text/html',\n '.htm': 'text/html',\n};\n\nconst DEFAULT_CONTENT_TYPE = 'application/octet-stream';\n\n/** Best-effort MIME sniff from the filename extension. Falls back to octet-stream. */\nexport function guessContentType(filename: string): string {\n const ext = extname(filename).toLowerCase();\n return CONTENT_TYPES[ext] ?? DEFAULT_CONTENT_TYPE;\n}\n\nfunction formatBytes(n: number): string {\n const mb = n / (1024 * 1024);\n return `${mb.toFixed(2)} MB (${n} bytes)`;\n}\n\n/**\n * Read a local file and shape it into a Graph fileAttachment POST body.\n * Throws OutlookCliError (not a silent truncation) if the file exceeds the\n * 3 MB inline-attachment ceiling — larger files need an upload session,\n * which is not implemented in v1 (docs/02 §6, \"Large files — upload session\").\n */\nexport async function readFileAttachment(\n path: string,\n): Promise<FileAttachmentUpload> {\n const stats = await stat(path);\n\n if (stats.size > MAX_INLINE_ATTACHMENT_BYTES) {\n throw new OutlookCliError(\n `Attachment \"${path}\" is ${formatBytes(stats.size)}, which exceeds the ` +\n `3 MB inline-attachment limit. Files between 3 MB and 150 MB require ` +\n `a Graph upload session (createUploadSession), which this CLI does ` +\n `not yet support. Choose a smaller file or split the content.`,\n );\n }\n\n const buf = await readFile(path);\n const name = basename(path);\n\n return {\n '@odata.type': '#microsoft.graph.fileAttachment',\n name,\n contentType: guessContentType(name),\n contentBytes: buf.toString('base64'),\n };\n}\n\nconst HTML_ENTITIES: Record<string, string> = {\n '&amp;': '&',\n '&lt;': '<',\n '&gt;': '>',\n '&quot;': '\"',\n '&#39;': \"'\",\n '&nbsp;': ' ',\n};\n\nconst ENTITY_RE = /&(?:amp|lt|gt|quot|#39|nbsp);/g;\n\n/**\n * Convert HTML to readable plain text. Not a full parser — strips script/style\n * blocks entirely, maps <br>/</p> to newlines, strips remaining tags, decodes\n * the common named entities, and collapses runs of blank lines.\n */\nexport function htmlToText(html: string): string {\n if (!html) return '';\n\n let text = html\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '');\n\n text = text\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<\\/p\\s*>/gi, '\\n\\n')\n .replace(/<\\/(div|tr|li|h[1-6])\\s*>/gi, '\\n')\n .replace(/<[^>]+>/g, '');\n\n text = text.replace(ENTITY_RE, (m) => HTML_ENTITIES[m] ?? m);\n\n text = text\n .split('\\n')\n .map((line) => line.replace(/[ \\t]+$/, ''))\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n\n return text;\n}\n","/**\n * Pure renderers: every function here returns a string. Nothing in this file\n * calls console.log — cli.ts owns printing. That split is what makes these\n * testable without capturing stdout.\n *\n * Graph omits fields liberally (S1/S8, docs/01-read-endpoints.md §6), so every\n * renderer treats optional/null fields as expected input, not an error case.\n */\n\nimport type {\n Attachment,\n Contact,\n MailFolder,\n Message,\n Recipient,\n UserProfile,\n} from './types.js';\nimport { htmlToText } from './mime.js';\n\nexport interface RenderOpts {\n json: boolean;\n}\n\nconst DATE_WIDTH = 20;\nconst FROM_WIDTH = 24;\nconst SUBJECT_WIDTH = 40;\n\nexport function renderJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\n/** \"Name <address>\" when a name is present, else the bare address. undefined if unresolvable. */\nfunction recipientLabel(recipient: Recipient | null | undefined): string | undefined {\n const address = recipient?.emailAddress?.address;\n if (!address) return undefined;\n const name = recipient.emailAddress.name;\n return name ? `${name} <${address}>` : address;\n}\n\nexport function formatRecipients(recipients?: Recipient[]): string {\n if (!recipients || recipients.length === 0) return '(none)';\n return recipients.map((r) => recipientLabel(r) ?? '(unknown)').join(', ');\n}\n\nfunction pad2(n: number): string {\n return n.toString().padStart(2, '0');\n}\n\n/** Deterministic UTC rendering so output doesn't vary with the host timezone. */\nexport function formatDate(iso?: string): string {\n if (!iso) return '(no date)';\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '(no date)';\n const y = d.getUTCFullYear();\n const mo = pad2(d.getUTCMonth() + 1);\n const day = pad2(d.getUTCDate());\n const h = pad2(d.getUTCHours());\n const mi = pad2(d.getUTCMinutes());\n return `${y}-${mo}-${day} ${h}:${mi} UTC`;\n}\n\nexport function truncate(text: string, max: number): string {\n if (max <= 0) return '';\n if (text.length <= max) return text;\n if (max === 1) return text.slice(0, 1);\n return `${text.slice(0, max - 1)}\\u2026`;\n}\n\nfunction subjectOf(message: Message): string {\n return message.subject && message.subject.trim().length > 0\n ? message.subject\n : '(no subject)';\n}\n\nfunction fromOf(message: Message): string {\n return recipientLabel(message.from ?? message.sender) ?? '(unknown sender)';\n}\n\n/**\n * Aligned columns: unread marker, date, from, subject, attachment marker, id.\n * `*` marks isRead === false; blank covers read or unknown (Graph can omit isRead).\n * `@` marks hasAttachments === true.\n */\nexport function renderMessageList(messages: Message[]): string {\n if (messages.length === 0) return '(no messages)';\n\n const header = [\n ' '.padEnd(1),\n 'DATE'.padEnd(DATE_WIDTH),\n 'FROM'.padEnd(FROM_WIDTH),\n 'SUBJECT'.padEnd(SUBJECT_WIDTH),\n ' '.padEnd(1),\n 'ID',\n ].join(' ');\n\n const rows = messages.map((m) => {\n const unread = m.isRead === false ? '*' : ' ';\n const attach = m.hasAttachments ? '@' : ' ';\n const date = formatDate(m.receivedDateTime ?? m.sentDateTime);\n const from = truncate(fromOf(m), FROM_WIDTH);\n const subject = truncate(subjectOf(m), SUBJECT_WIDTH);\n return [\n unread,\n date.padEnd(DATE_WIDTH),\n from.padEnd(FROM_WIDTH),\n subject.padEnd(SUBJECT_WIDTH),\n attach,\n m.id,\n ].join(' ');\n });\n\n return [header, ...rows].join('\\n');\n}\n\nfunction readState(message: Message): string {\n if (message.isRead === false) return 'no';\n if (message.isRead === true) return 'yes';\n return 'unknown';\n}\n\nfunction renderBody(message: Message, opts?: { html?: boolean }): string {\n const body = message.body;\n if (!body || !body.content) {\n return message.bodyPreview && message.bodyPreview.trim().length > 0\n ? message.bodyPreview\n : '(no body)';\n }\n if (body.contentType === 'html') {\n return opts?.html ? body.content : htmlToText(body.content);\n }\n return body.content;\n}\n\n/** Full headers, then a blank line, then the body (plain text unless opts.html). */\nexport function renderMessage(message: Message, opts?: { html?: boolean }): string {\n const lines: string[] = [\n `Subject: ${subjectOf(message)}`,\n `From: ${fromOf(message)}`,\n `To: ${formatRecipients(message.toRecipients)}`,\n ];\n\n if (message.ccRecipients && message.ccRecipients.length > 0) {\n lines.push(`Cc: ${formatRecipients(message.ccRecipients)}`);\n }\n\n lines.push(\n `Date: ${formatDate(message.receivedDateTime ?? message.sentDateTime)}`,\n `Importance: ${message.importance ?? 'normal'}`,\n `Read: ${readState(message)}`,\n `Attachments: ${message.hasAttachments ? 'yes' : 'no'}`,\n `Id: ${message.id}`,\n '',\n renderBody(message, opts),\n );\n\n return lines.join('\\n');\n}\n\nexport function renderFolders(folders: MailFolder[]): string {\n if (folders.length === 0) return '(no folders)';\n\n return folders\n .map((f) => {\n const name = f.displayName && f.displayName.trim() ? f.displayName : '(unnamed folder)';\n const counts: string[] = [];\n if (f.unreadItemCount !== undefined) counts.push(`${f.unreadItemCount} unread`);\n if (f.totalItemCount !== undefined) counts.push(`${f.totalItemCount} total`);\n const suffix = counts.length > 0 ? ` (${counts.join(', ')})` : '';\n return `${name}${suffix} — ${f.id}`;\n })\n .join('\\n');\n}\n\n/** Strips a leading '#' and the 'microsoft.graph.' prefix (S9's own example omits the '#'). */\nfunction attachmentKind(odataType?: string): string {\n if (!odataType) return 'unknown';\n const normalized = odataType.replace(/^#/, '');\n switch (normalized) {\n case 'microsoft.graph.fileAttachment':\n return 'file';\n case 'microsoft.graph.itemAttachment':\n return 'item';\n case 'microsoft.graph.referenceAttachment':\n return 'reference';\n default:\n return normalized;\n }\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport function renderAttachments(attachments: Attachment[]): string {\n if (attachments.length === 0) return '(no attachments)';\n\n return attachments\n .map((a) => {\n const name = a.name && a.name.trim() ? a.name : '(unnamed attachment)';\n const kind = attachmentKind(a['@odata.type']);\n const size = a.size !== undefined ? formatSize(a.size) : '(unknown size)';\n const inline = a.isInline ? ' [inline]' : '';\n return `${name} — ${kind}, ${size}${inline} — ${a.id}`;\n })\n .join('\\n');\n}\n\nexport function renderProfile(profile: UserProfile): string {\n const lines = [\n `Name: ${profile.displayName ?? '(unknown)'}`,\n `Mail: ${profile.mail ?? profile.userPrincipalName ?? '(none)'}`,\n ];\n if (profile.jobTitle) lines.push(`Job title: ${profile.jobTitle}`);\n lines.push(`Id: ${profile.id}`);\n return lines.join('\\n');\n}\n\n// ── Contact rendering ────────────────────────────────────────────────\n\nconst NAME_WIDTH = 24;\nconst PHONE_WIDTH = 18;\nconst EMAIL_WIDTH = 28;\nconst COMPANY_WIDTH = 20;\n\n/** First non-empty phone across mobile → business → home, with a label prefix. */\nfunction primaryPhone(contact: Contact): string {\n if (contact.mobilePhone) return contact.mobilePhone;\n if (contact.businessPhones && contact.businessPhones.length > 0) return contact.businessPhones[0]!;\n if (contact.homePhones && contact.homePhones.length > 0) return contact.homePhones[0]!;\n return '';\n}\n\n/** First email address, if any. */\nfunction primaryEmail(contact: Contact): string {\n if (contact.emailAddresses && contact.emailAddresses.length > 0) {\n return contact.emailAddresses[0]!.address ?? '';\n }\n return '';\n}\n\n/**\n * Aligned columns: NAME, PHONE, EMAIL, COMPANY, ID.\n * Uses truncate() for long fields to keep output scannable.\n */\nexport function renderContactList(contacts: Contact[]): string {\n if (contacts.length === 0) return '(no contacts)';\n\n const header = [\n 'NAME'.padEnd(NAME_WIDTH),\n 'PHONE'.padEnd(PHONE_WIDTH),\n 'EMAIL'.padEnd(EMAIL_WIDTH),\n 'COMPANY'.padEnd(COMPANY_WIDTH),\n 'ID',\n ].join(' ');\n\n const rows = contacts.map((c) => {\n const name = truncate(c.displayName ?? '(unnamed)', NAME_WIDTH);\n const phone = truncate(primaryPhone(c), PHONE_WIDTH);\n const email = truncate(primaryEmail(c), EMAIL_WIDTH);\n const company = truncate(c.companyName ?? '', COMPANY_WIDTH);\n return [\n name.padEnd(NAME_WIDTH),\n phone.padEnd(PHONE_WIDTH),\n email.padEnd(EMAIL_WIDTH),\n company.padEnd(COMPANY_WIDTH),\n c.id,\n ].join(' ');\n });\n\n return [header, ...rows].join('\\n');\n}\n\n/** Combine all phone numbers with labels: mobile, business, home. */\nfunction allPhones(contact: Contact): string {\n const parts: string[] = [];\n if (contact.mobilePhone) parts.push(`${contact.mobilePhone} (mobile)`);\n if (contact.businessPhones) {\n for (const p of contact.businessPhones) parts.push(`${p} (business)`);\n }\n if (contact.homePhones) {\n for (const p of contact.homePhones) parts.push(`${p} (home)`);\n }\n return parts.length > 0 ? parts.join(', ') : '(none)';\n}\n\n/** All email addresses, comma-separated. */\nfunction allEmails(contact: Contact): string {\n if (!contact.emailAddresses || contact.emailAddresses.length === 0) return '(none)';\n return contact.emailAddresses\n .map((e) => {\n const addr = e.address ?? '(unknown)';\n return e.name ? `${e.name} <${addr}>` : addr;\n })\n .join(', ');\n}\n\n/** Full detail view of a single contact, similar to renderMessage. */\nexport function renderContact(contact: Contact): string {\n const lines: string[] = [\n `Name: ${contact.displayName ?? '(unnamed)'}`,\n `Email: ${allEmails(contact)}`,\n `Phone: ${allPhones(contact)}`,\n ];\n if (contact.companyName) lines.push(`Company: ${contact.companyName}`);\n if (contact.jobTitle) lines.push(`Job title: ${contact.jobTitle}`);\n if (contact.department) lines.push(`Department: ${contact.department}`);\n if (contact.personalNotes) lines.push(`Notes: ${contact.personalNotes}`);\n lines.push(`Id: ${contact.id}`);\n return lines.join('\\n');\n}\n","/**\n * `@odata.nextLink` pagination (docs/01-read-endpoints.md §5).\n *\n * The nextLink is a complete, pre-encoded absolute URL — GraphClient's\n * buildUrl already special-cases an absolute `path` to pass it straight\n * through unmodified (no base-URL re-prefixing, no query re-merge). That's\n * what makes following it \"verbatim\" here rather than reconstructing it.\n */\n\nimport type { GraphClient } from './client.js';\nimport type { GraphCollection } from './types.js';\n\n/** Flat item stream across every page reachable by following nextLink. */\nexport async function* pageItems<T>(\n client: GraphClient,\n path: string,\n query?: Record<string, unknown>,\n): AsyncGenerator<T> {\n const seen = new Set<string>();\n let url: string | undefined = path;\n let urlQuery: Record<string, unknown> | undefined = query;\n\n while (url !== undefined) {\n if (seen.has(url)) {\n // Non-advancing or self-referential nextLink — stop rather than spin.\n return;\n }\n seen.add(url);\n\n // Route through buildSpec+request (not the narrower `get<T>(path, query)`\n // overload) since this function's query type is the wider\n // Record<string, unknown> mandated by the paginate.ts contract.\n const spec = client.buildSpec('GET', url, undefined, urlQuery);\n const page: GraphCollection<T> = await client.request<GraphCollection<T>>(spec);\n for (const item of page.value) {\n yield item;\n }\n\n url = page['@odata.nextLink'];\n // nextLink already carries every original query param re-encoded; never\n // re-append the caller's original query on subsequent pages.\n urlQuery = undefined;\n }\n}\n\nexport interface CollectItemsOptions {\n query?: Record<string, unknown>;\n /** Stop as soon as this many items are collected — truncates mid-page. */\n limit?: number;\n /** Follow every nextLink to exhaustion. Ignored when `limit` is set. */\n all?: boolean;\n}\n\nexport async function collectItems<T>(\n client: GraphClient,\n path: string,\n opts?: CollectItemsOptions,\n): Promise<T[]> {\n const { query, limit, all } = opts ?? {};\n\n if (limit === undefined && !all) {\n // Default: exactly one page, no nextLink follow at all.\n const spec = client.buildSpec('GET', path, undefined, query);\n const page = await client.request<GraphCollection<T>>(spec);\n return [...page.value];\n }\n\n const results: T[] = [];\n for await (const item of pageItems<T>(client, path, query)) {\n results.push(item);\n if (limit !== undefined && results.length >= limit) break;\n }\n return results;\n}\n","/**\n * Turn an attacker-controlled filename into one that is safe to create on\n * ANY host filesystem — specifically including Windows, whose rules are\n * stricter than POSIX in ways that are easy to miss on a mac.\n *\n * The name on a Graph attachment is remote data chosen by whoever sent the\n * mail. `basename()` alone defeats `../` traversal, but leaves a family of\n * Windows-only hazards intact:\n *\n * `report:secret` -> NTFS alternate data stream; the bytes after the colon\n * vanish from an ordinary directory listing.\n * `CON`, `NUL`, -> reserved DOS device names. Opening one addresses the\n * `AUX`, `COM1` DEVICE, not a file; the write can hang or be discarded.\n * `invoice.pdf.` -> trailing dot/space is silently stripped by Win32, so\n * `invoice.pdf ` two distinct attachments collapse onto one path.\n * `<`, `>`, `|`, -> outright illegal in a Win32 filename.\n * `\"`, `*`, `?`\n *\n * Applied unconditionally rather than behind a `process.platform` check: a\n * name that is dangerous on Windows is merely ugly on POSIX, and downloads\n * synced or copied between machines should not change meaning en route.\n */\n\n/** Illegal on Win32, plus the ADS colon. Control chars 0x00-0x1f too. */\n// eslint-disable-next-line no-control-regex\nconst ILLEGAL_CHARS_RE = /[<>:\"|?*\\u0000-\\u001f]/g;\n\n/** DOS device names, with or without an extension (`CON`, `CON.txt`). */\nconst RESERVED_NAMES = new Set([\n 'con',\n 'prn',\n 'aux',\n 'nul',\n ...Array.from({ length: 9 }, (_, i) => `com${i + 1}`),\n ...Array.from({ length: 9 }, (_, i) => `lpt${i + 1}`),\n]);\n\n/** Win32 MAX_PATH leaves little room; keep a component well under it. */\nconst MAX_COMPONENT_LENGTH = 180;\n\nfunction stem(name: string): string {\n const dot = name.indexOf('.');\n return dot === -1 ? name : name.slice(0, dot);\n}\n\n/**\n * @param name the raw, untrusted filename (already basename'd by caller)\n * @param fallback used when sanitizing leaves nothing usable\n */\nexport function sanitizeFilename(name: string, fallback: string): string {\n let out = name.replace(ILLEGAL_CHARS_RE, '_');\n\n // Win32 strips these silently, which would let `a.pdf` and `a.pdf.` collide.\n out = out.replace(/[. ]+$/, '');\n out = out.trim();\n\n if (out === '' || out === '.' || out === '..') return fallback;\n\n // Prefix rather than replace, so the original name stays legible.\n if (RESERVED_NAMES.has(stem(out).toLowerCase())) {\n out = `_${out}`;\n }\n\n if (out.length > MAX_COMPONENT_LENGTH) {\n // Preserve the extension — it is what makes the file openable.\n const lastDot = out.lastIndexOf('.');\n const ext = lastDot > 0 ? out.slice(lastDot, lastDot + 16) : '';\n out = out.slice(0, MAX_COMPONENT_LENGTH - ext.length) + ext;\n }\n\n // Re-check: truncation can re-expose a trailing dot or space.\n out = out.replace(/[. ]+$/, '');\n return out === '' ? fallback : out;\n}\n","/**\n * `outlook auth <subcommand>` — local credential lifecycle: login, status,\n * logout, refresh. Every other command in this CLI depends on this one:\n * without `outlook auth login` there is no cached token for `ctx.auth`\n * (auth.ts) to hand out, so nothing else can call Graph.\n *\n * Subcommand is positional 0 (`status` is the default when absent, since\n * \"is anything even signed in?\" is the harmless, side-effect-free question\n * to default to). Unknown subcommands are a UsageError listing the valid\n * ones.\n *\n * `mutating: false` on all four subcommands: they change LOCAL credential\n * cache state (a file under tokenStore.ts), never remote mailbox state.\n * `guardMutation`/`--dry-run` exist to protect a real mailbox from a\n * surprising Graph call (send/delete/move) — a local-only side effect has\n * nothing for --dry-run to preview or protect against, so this command\n * deliberately does not wrap itself in guardMutation (see command.ts's own\n * doc comment: that chokepoint is for state-changing *Graph* calls).\n *\n * SECURITY: never print accessToken, refreshToken, or any client secret.\n * Every render path below is built from an explicit allow-list of fields\n * (signedIn, expired, account, expiresAt, scopes) — the raw TokenSet /\n * AuthStatus objects from auth.ts are never handed whole to emit()/out(),\n * specifically so a future field added to either type can't silently start\n * leaking through this command.\n */\n\nimport { emit, type CommandContext, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport { parseScopeList } from '../scopes.js';\nimport { FILE_MODE_IS_ENFORCED } from '../tokenStore.js';\nimport type { DeviceCodeResponse, GrantMode, TokenSet } from '../types.js';\n\nconst SUBCOMMANDS = ['login', 'status', 'logout', 'refresh'] as const;\n\n/** Non-secret facts we're willing to show the user, shared by all four subcommands. */\ninterface AuthFacts {\n signedIn: boolean;\n expired?: boolean;\n account?: string;\n expiresAt?: number;\n scopes?: string;\n mode?: GrantMode;\n grantScopes?: string[];\n}\n\nfunction renderFacts(facts: AuthFacts): string {\n const lines = [`Signed in: ${facts.signedIn ? 'yes' : 'no'}`];\n if (facts.expired !== undefined) lines.push(`Expired: ${facts.expired ? 'yes' : 'no'}`);\n if (facts.account) lines.push(`Account: ${facts.account}`);\n if (facts.expiresAt !== undefined) lines.push(`Expires: ${new Date(facts.expiresAt).toISOString()}`);\n if (facts.scopes) lines.push(`Scopes: ${facts.scopes}`);\n if (facts.grantScopes) lines.push(`Requested scopes (--scopes): ${facts.grantScopes.join(' ')}`);\n if (facts.mode) {\n lines.push(\n `Access: ${facts.mode === 'readonly' ? 'read-only (cannot send or delete)' : 'full read/write'}`,\n );\n }\n return lines.join('\\n');\n}\n\n/** Non-secret projection of a freshly issued/refreshed TokenSet — drops accessToken/refreshToken/tokenType. */\nfunction factsFromTokenSet(tokens: TokenSet): AuthFacts {\n return {\n signedIn: true,\n ...(tokens.account !== undefined ? { account: tokens.account } : {}),\n expiresAt: tokens.expiresAt,\n ...(tokens.scope !== undefined ? { scopes: tokens.scope } : {}),\n ...(tokens.mode !== undefined ? { mode: tokens.mode } : {}),\n ...(tokens.grantScopes !== undefined ? { grantScopes: tokens.grantScopes } : {}),\n };\n}\n\n/**\n * The device-code prompt IS the login UX — printed the moment auth.login()\n * hands it back, before the (potentially slow) polling loop even starts.\n * Prefers the server's own pre-formatted `message` (it already names both\n * the URL and the code); falls back to assembling one from the two fields\n * that actually matter if the server omits it.\n */\nfunction printDevicePrompt(ctx: CommandContext, device: DeviceCodeResponse): void {\n ctx.out(\n device.message ??\n `To sign in, open ${device.verification_uri} and enter the code: ${device.user_code}`,\n );\n}\n\nasync function loginHandler(ctx: CommandContext): Promise<void> {\n const readOnly = ctx.args.bool('readonly');\n const scopes = scopesFlag(ctx);\n if (readOnly && scopes !== undefined) {\n throw new UsageError('--readonly and --scopes cannot be combined; list the read scopes you want in --scopes.');\n }\n const tokens = await ctx.auth.login(\n (device) => printDevicePrompt(ctx, device),\n { readOnly, ...(scopes !== undefined ? { scopes } : {}) },\n );\n\n // The stored refresh token is only as private as the file holding it, and\n // on Windows the 0600 we request is not actually enforced. Say so once, at\n // the moment the secret is created, rather than implying a guarantee.\n if (!FILE_MODE_IS_ENFORCED) {\n ctx.err(\n 'warning: on Windows the token cache cannot be restricted to your user ' +\n 'account by file mode alone. Restrict the containing directory with an ' +\n 'ACL, or sign in with --readonly to limit what a stolen token can do.',\n );\n }\n\n const facts = factsFromTokenSet(tokens);\n emit(ctx, facts, () => `Signed in.\\n${renderFacts(facts)}`);\n}\n\nasync function statusHandler(ctx: CommandContext): Promise<void> {\n const status = await ctx.auth.status();\n emit(ctx, status, () => renderFacts(status));\n}\n\nasync function logoutHandler(ctx: CommandContext): Promise<void> {\n await ctx.auth.logout();\n emit(ctx, { signedIn: false }, () => 'Signed out.');\n}\n\nasync function refreshHandler(ctx: CommandContext): Promise<void> {\n const tokens = await ctx.auth.refresh();\n const facts = factsFromTokenSet(tokens);\n emit(ctx, facts, () => `Token refreshed.\\n${renderFacts(facts)}`);\n}\n\n/** `--scopes a,b,c`, normalized; undefined when the flag is absent. */\nfunction scopesFlag(ctx: CommandContext): string[] | undefined {\n if (!ctx.args.has('scopes')) return undefined;\n const raw = ctx.args.str('scopes');\n if (raw === undefined) {\n throw new UsageError('--scopes requires a comma-separated list, e.g. --scopes Mail.ReadWrite');\n }\n return parseScopeList(raw);\n}\n\nasync function authHandler(ctx: CommandContext): Promise<void> {\n // Note: ParsedArgs.str(name, fallback) keys off a *named* flag (--name),\n // not a positional index — positionals are read directly off the array.\n const subcommand = ctx.args.positionals[0] ?? 'status';\n if (subcommand !== 'login' && ctx.args.has('scopes')) {\n throw new UsageError(\n '--scopes applies only to \"outlook auth login\"; refresh reuses the scope set recorded at login.',\n );\n }\n switch (subcommand) {\n case 'login':\n return loginHandler(ctx);\n case 'status':\n return statusHandler(ctx);\n case 'logout':\n return logoutHandler(ctx);\n case 'refresh':\n return refreshHandler(ctx);\n default:\n throw new UsageError(\n `Unknown \"outlook auth\" subcommand: \"${subcommand}\". Valid subcommands: ${SUBCOMMANDS.join(', ')}.`,\n );\n }\n}\n\nexport const authCommand: CommandSpec = {\n name: 'auth',\n summary: 'Manage local sign-in: login, status, logout, refresh',\n usage:\n 'outlook auth [login|status|logout|refresh] [--readonly | --scopes <list>] [--json]\\n' +\n '\\n' +\n ' --readonly On login: request Mail.Read instead of Mail.ReadWrite and\\n' +\n ' drop Mail.Send, so the stored token cannot send, delete, or\\n' +\n ' modify mail. Recommended for unattended/agent use.\\n' +\n ' --scopes On login: request exactly these comma-separated scopes\\n' +\n ' (offline_access is added if missing). The set is stored\\n' +\n ' with the token and reused by refresh. Pair with\\n' +\n ' GRAPH_TOKEN_CACHE to keep a narrow token in its own file.',\n mutating: false,\n handler: authHandler,\n};\n","/**\n * `outlook contacts <subcommand>` — read-only access to the user's contacts\n * via Microsoft Graph v1.0 `/me/contacts`.\n *\n * Subcommand is positional 0 (`list` is the default when absent).\n * Unknown subcommands are a UsageError listing the valid ones.\n *\n * `mutating: false` — entirely read-only. No `guardMutation` needed.\n *\n * Search uses `$filter=startswith(displayName,'<query>')` rather than\n * `$search=\"displayName:{query}\"` — the latter requires a\n * `ConsistencyLevel: eventual` header which would need client.ts changes.\n *\n * NOTE: the `Contacts.Read` scope is required. Users upgrading from a\n * previous version must re-login (`outlook auth logout && outlook auth login`)\n * to pick up the new scope.\n */\n\nimport { emit, type CommandContext, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport { renderContact, renderContactList } from '../output.js';\nimport { collectItems } from '../paginate.js';\nimport type { Contact } from '../types.js';\n\nconst SUBCOMMANDS = ['list', 'get', 'search'] as const;\n\nconst DEFAULT_SELECT =\n 'id,displayName,emailAddresses,mobilePhone,businessPhones,homePhones,companyName,jobTitle';\nconst DEFAULT_ORDERBY = 'displayName asc';\nconst MAX_TOP = 1000;\n\nfunction readTop(ctx: CommandContext): number {\n if (!ctx.args.has('top')) return 25;\n const top = ctx.args.num('top');\n if (top === undefined || !Number.isInteger(top) || top < 1 || top > MAX_TOP) {\n throw new UsageError(`--top must be an integer between 1 and ${MAX_TOP}`);\n }\n return top;\n}\n\nfunction readLimit(ctx: CommandContext, fallback: number): number {\n if (!ctx.args.has('limit')) return fallback;\n const limit = ctx.args.num('limit');\n if (limit === undefined || !Number.isInteger(limit) || limit < 1 || limit > MAX_TOP) {\n throw new UsageError(`--limit must be an integer between 1 and ${MAX_TOP}`);\n }\n return limit;\n}\n\nasync function listHandler(ctx: CommandContext): Promise<void> {\n const top = readTop(ctx);\n const all = ctx.args.bool('all');\n const limit = readLimit(ctx, top);\n const select = ctx.args.str('select') ?? DEFAULT_SELECT;\n\n const query: Record<string, unknown> = {\n $select: select,\n $orderby: DEFAULT_ORDERBY,\n $top: top,\n };\n\n const filter = ctx.args.str('filter');\n if (filter) query.$filter = filter;\n\n const contacts = await collectItems<Contact>(ctx.client, '/me/contacts', {\n query,\n limit: all ? undefined : limit,\n all,\n });\n\n emit(ctx, contacts, () => renderContactList(contacts));\n}\n\nasync function getHandler(ctx: CommandContext): Promise<void> {\n const id = ctx.args.requirePositional(1, '<contactId>');\n const path = `/me/contacts/${encodeURIComponent(id)}`;\n\n const contact = await ctx.client.get<Contact>(path);\n\n emit(ctx, contact, () => renderContact(contact));\n}\n\nasync function searchHandler(ctx: CommandContext): Promise<void> {\n const query = ctx.args.requirePositional(1, '<query>');\n const top = readTop(ctx);\n\n // Use $filter with startswith — no ConsistencyLevel header needed.\n const escaped = query.replace(/'/g, \"''\");\n const filterExpr = `startswith(displayName,'${escaped}')`;\n\n const contacts = await collectItems<Contact>(ctx.client, '/me/contacts', {\n query: {\n $select: DEFAULT_SELECT,\n $filter: filterExpr,\n $top: top,\n },\n limit: top,\n });\n\n emit(ctx, contacts, () => renderContactList(contacts));\n}\n\nasync function contactsHandler(ctx: CommandContext): Promise<void> {\n const subcommand = ctx.args.positionals[0] ?? 'list';\n switch (subcommand) {\n case 'list':\n return listHandler(ctx);\n case 'get':\n return getHandler(ctx);\n case 'search':\n return searchHandler(ctx);\n default:\n throw new UsageError(\n `Unknown \"outlook contacts\" subcommand: \"${subcommand}\". Valid subcommands: ${SUBCOMMANDS.join(', ')}.`,\n );\n }\n}\n\nexport const contactsCommand: CommandSpec = {\n name: 'contacts',\n summary: 'List, get, or search contacts (read-only)',\n usage:\n 'outlook contacts [list|get|search] [<id|query>] [--top <n>] [--all] [--limit <n>] [--select <fields>] [--filter <expr>] [--json]',\n mutating: false,\n handler: contactsHandler,\n};\n","/**\n * Email signatures.\n *\n * Microsoft Graph never applies the user's Outlook signature to mail sent\n * through the API (signatures are injected client-side by Outlook, and\n * mailboxSettings exposes no signature field), so the CLI appends one itself.\n *\n * Resolution, per invocation:\n * --no-signature -> none (explicit opt-out always wins)\n * --signature <path> -> that file (.html/.htm = HTML, else text)\n * OUTLOOK_SIGNATURE_FILE -> plain-text signature\n * OUTLOOK_SIGNATURE_HTML_FILE -> HTML signature\n * nothing configured -> none\n *\n * Default-on once configured is deliberate: forgetting a flag must not mean\n * unsigned mail. Every surface reports `signatureApplied` in --json output and\n * --dry-run shows the appended text, so the behaviour is never invisible.\n *\n * A configured file that cannot be read is a hard error, not a silent skip:\n * sending unsigned mail when the user asked for a signature is the surprise.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type { ParsedArgs } from './args.js';\nimport { UsageError } from './errors.js';\nimport type { ItemBody } from './types.js';\n\nexport type EnvLike = Readonly<Record<string, string | undefined>>;\n\nexport const SIGNATURE_TEXT_ENV = 'OUTLOOK_SIGNATURE_FILE';\nexport const SIGNATURE_HTML_ENV = 'OUTLOOK_SIGNATURE_HTML_FILE';\n\n/** RFC 3676 §4.3 signature separator (\"-- \" with the trailing space). */\nexport const TEXT_DELIMITER = '-- ';\n\nexport interface Signature {\n text?: string;\n html?: string;\n}\n\nfunction trimmed(value: string | undefined): string | undefined {\n const t = value?.trim();\n return t ? t : undefined;\n}\n\nfunction isHtmlPath(path: string): boolean {\n return /\\.html?$/i.test(path);\n}\n\nasync function readSignatureFile(path: string, origin: string): Promise<string> {\n try {\n const content = await readFile(path, 'utf8');\n // An all-whitespace file is a misconfiguration, not a valid empty sig.\n if (content.trim() === '') {\n throw new UsageError(\n `Signature file ${path} (from ${origin}) is empty. ` +\n 'Add content, or pass --no-signature to send without one.',\n );\n }\n return content;\n } catch (e) {\n if (e instanceof UsageError) throw e;\n const reason = e instanceof Error ? e.message : String(e);\n throw new UsageError(\n `Could not read signature file ${path} (from ${origin}): ${reason}\\n` +\n 'Fix the path, or pass --no-signature to send without one.',\n );\n }\n}\n\n/**\n * Decide which signature (if any) applies. `--signature` and `--no-signature`\n * share the key `signature`: args.ts records `--no-x` as `x=false`.\n */\nexport async function resolveSignature(\n args: ParsedArgs,\n env: EnvLike = {},\n): Promise<Signature | undefined> {\n if (args.has('signature')) {\n const path = args.str('signature');\n if (path === undefined) {\n // A string means a path; anything else is a boolean. `bool()` throws\n // on ambiguous values, which is what we want for `--signature=maybe`.\n if (!args.bool('signature')) return undefined; // --no-signature\n throw new UsageError(\n '--signature needs a file path (e.g. --signature ~/sig.txt). ' +\n 'Use --no-signature to send without one.',\n );\n }\n if (path.trim() === '' || /^(false|0|no|off)$/i.test(path.trim())) {\n return undefined; // --signature=false and friends\n }\n const content = await readSignatureFile(path, '--signature');\n return isHtmlPath(path) ? { html: content } : { text: content };\n }\n\n const textPath = trimmed(env[SIGNATURE_TEXT_ENV]);\n const htmlPath = trimmed(env[SIGNATURE_HTML_ENV]);\n if (textPath === undefined && htmlPath === undefined) return undefined;\n\n const sig: Signature = {};\n if (textPath !== undefined) {\n sig.text = await readSignatureFile(textPath, SIGNATURE_TEXT_ENV);\n }\n if (htmlPath !== undefined) {\n sig.html = await readSignatureFile(htmlPath, SIGNATURE_HTML_ENV);\n }\n return sig;\n}\n\n/** True when the user asked FOR a signature via flag (path or bare --signature). */\nexport function signatureFlagRequested(args: ParsedArgs): boolean {\n if (!args.has('signature')) return false;\n const v = args.str('signature');\n if (v === undefined) return args.bool('signature');\n return !(v.trim() === '' || /^(false|0|no|off)$/i.test(v.trim()));\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\n/** Append a plain-text signature with the RFC 3676 delimiter. */\nexport function appendTextSignature(content: string, sig: Signature): string {\n if (sig.text === undefined) {\n throw new UsageError(\n 'Only an HTML signature is configured, but this message body is plain ' +\n `text. Set ${SIGNATURE_TEXT_ENV}, pass --html (send/draft), ` +\n 'or pass --no-signature.',\n );\n }\n const head = content.trimEnd();\n const tail = `${TEXT_DELIMITER}\\n${sig.text.trimEnd()}`;\n return head === '' ? tail : `${head}\\n\\n${tail}`;\n}\n\n/**\n * Append an HTML signature, inside </body> when the body has one.\n *\n * Trust boundary: `sig.html` is inserted verbatim without sanitisation.\n * This is intentional — the file belongs to the user and may contain\n * arbitrary HTML (images, inline styles, etc.). Treat it like the token\n * cache: it should be writable only by its owner (`chmod 600`). Do not\n * point this at untrusted or world-writable paths.\n */\nfunction appendHtmlSignature(content: string, sig: Signature): string {\n const html =\n sig.html?.trim() ??\n escapeHtml((sig.text ?? '').trimEnd()).replace(/\\r?\\n/g, '<br>');\n const block = `<br><div class=\"outlook-cli-signature\">${html}</div>`;\n\n // Search the original string case-insensitively. Searching a lowercased\n // copy breaks when lowercasing changes length (U+0130 \"İ\" becomes two code\n // units), shifting the splice into the middle of the tag.\n const matches = [...content.matchAll(/<\\/body>/gi)];\n const last = matches[matches.length - 1];\n if (last?.index === undefined) return `${content}${block}`;\n return `${content.slice(0, last.index)}${block}${content.slice(last.index)}`;\n}\n\n/** Return a new body with the signature appended in the body's own format. */\nexport function applySignature(body: ItemBody, sig: Signature): ItemBody {\n const content =\n body.contentType.toLowerCase() === 'html'\n ? appendHtmlSignature(body.content, sig)\n : appendTextSignature(body.content, sig);\n return { contentType: body.contentType, content };\n}\n","/**\n * Shared composition helpers for send / reply / forward / draft.\n *\n * Recipient parsing, body building and attachment loading live here exactly\n * once so the four compose surfaces cannot drift apart — a recipient bug\n * fixed in `send` must not still be live in `forward`.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type { ParsedArgs } from '../args.js';\nimport { UsageError } from '../errors.js';\nimport { readFileAttachment } from '../mime.js';\nimport { applySignature, type Signature } from '../signature.js';\nimport type {\n BodyContentType,\n FileAttachmentUpload,\n ItemBody,\n Recipient,\n} from '../types.js';\n\n/**\n * Accepts both repeated flags (`--to a --to b`) and comma-separated values\n * (`--to \"a,b\"`), because both are things people actually type.\n */\nexport function parseRecipients(\n values: readonly string[],\n flag: string,\n): Recipient[] {\n const out: Recipient[] = [];\n for (const value of values) {\n for (const part of value.split(',')) {\n const address = part.trim();\n if (address.length === 0) continue;\n if (!address.includes('@')) {\n throw new UsageError(\n `--${flag} received \"${address}\", which is not an email address.`,\n );\n }\n out.push({ emailAddress: { address } });\n }\n }\n return out;\n}\n\nexport function recipientsFromArgs(args: ParsedArgs, flag: string): Recipient[] {\n return parseRecipients(args.strAll(flag), flag);\n}\n\n/** `--body <text>` or `--body-file <path>`, never both. */\nexport async function buildBody(\n args: ParsedArgs,\n): Promise<ItemBody | undefined> {\n const inline = args.str('body');\n const file = args.str('body-file');\n\n if (inline !== undefined && file !== undefined) {\n throw new UsageError('Use either --body or --body-file, not both.');\n }\n\n const content = file !== undefined ? await readFile(file, 'utf8') : inline;\n if (content === undefined) return undefined;\n\n // Graph accepts either casing; we author lowercase (docs/02).\n const contentType: BodyContentType = args.bool('html') ? 'html' : 'text';\n return { contentType, content };\n}\n\n/** Each --attach is read and base64-encoded. Over 3 MB throws (mime.ts). */\nexport async function loadAttachments(\n args: ParsedArgs,\n): Promise<FileAttachmentUpload[]> {\n const out: FileAttachmentUpload[] = [];\n for (const path of args.strAll('attach')) {\n out.push(await readFileAttachment(path));\n }\n return out;\n}\n\nexport interface ComposedMessage {\n subject?: string;\n body?: ItemBody;\n toRecipients?: Recipient[];\n ccRecipients?: Recipient[];\n bccRecipients?: Recipient[];\n attachments?: FileAttachmentUpload[];\n}\n\n/** Build the `message` object shared by sendMail and draft create/update. */\nexport async function composeMessage(\n args: ParsedArgs,\n): Promise<ComposedMessage> {\n const message: ComposedMessage = {};\n\n const subject = args.str('subject');\n if (subject !== undefined) message.subject = subject;\n\n const body = await buildBody(args);\n if (body !== undefined) message.body = body;\n\n const to = recipientsFromArgs(args, 'to');\n if (to.length > 0) message.toRecipients = to;\n\n const cc = recipientsFromArgs(args, 'cc');\n if (cc.length > 0) message.ccRecipients = cc;\n\n const bcc = recipientsFromArgs(args, 'bcc');\n if (bcc.length > 0) message.bccRecipients = bcc;\n\n const attachments = await loadAttachments(args);\n if (attachments.length > 0) message.attachments = attachments;\n\n return message;\n}\n\n/**\n * Apply a resolved signature to an already-composed message (mutates).\n *\n * Extracted from composeMessage so callers can run --to/--subject validation\n * and the 'Nothing to create' check BEFORE the signature file is even touched.\n *\n * Precondition: `args` must be the same ParsedArgs object that was used to\n * build `message` (i.e. `ctx.args`). When the message has no body yet, the\n * body's content-type is derived from `args.bool('html')`; if `args` were a\n * different object the format could disagree with the rest of the message.\n * Every current caller satisfies this by passing `ctx.args` directly.\n *\n * The `Object.keys(message).length === 0` guard exists for `draft create`:\n * that command checks for an empty message and exits with \"Nothing to create\"\n * before reaching the signature step. Returning early here preserves that\n * check — `send` never reaches this branch because it validates --to and\n * --subject first.\n */\nexport function signMessage(\n message: ComposedMessage,\n signature: Signature | undefined,\n args: ParsedArgs,\n): void {\n if (signature === undefined || Object.keys(message).length === 0) return;\n const base: ItemBody = message.body ?? {\n contentType: args.bool('html') ? 'html' : 'text',\n content: '',\n };\n message.body = applySignature(base, signature);\n}\n\n/**\n * Default true. `--no-save-sent` is parsed by args.ts into `save-sent=false`,\n * so we probe the de-prefixed name.\n */\nexport function saveToSentItems(args: ParsedArgs): boolean {\n return args.has('save-sent') ? args.bool('save-sent') : true;\n}\n\n/** Summarize recipients for the human-readable confirmation line. */\nexport function describeRecipients(recipients?: Recipient[]): string {\n if (!recipients || recipients.length === 0) return '(none)';\n return recipients.map((r) => r.emailAddress.address).join(', ');\n}\n","/**\n * `outlook draft list|create|update|send`.\n *\n * The draft lifecycle is the SAFE way to send mail: create, inspect, then\n * send as a separate deliberate step. `draft send` is irreversible and is\n * guarded; `draft list` is a plain read.\n */\n\nimport { emit, guardMutation, type CommandContext, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport { collectItems } from '../paginate.js';\nimport { renderMessageList } from '../output.js';\nimport { resolveSignature, signatureFlagRequested } from '../signature.js';\nimport type { Message } from '../types.js';\nimport { composeMessage, signMessage } from './compose.js';\n\nconst DRAFTS_PATH = '/me/mailFolders/drafts/messages';\nconst SUBCOMMANDS = ['list', 'create', 'update', 'send'] as const;\n\nasync function listDrafts(ctx: CommandContext): Promise<void> {\n const limit = ctx.args.num('limit');\n const messages = await collectItems<Message>(ctx.client, DRAFTS_PATH, {\n query: {\n $select: 'id,subject,toRecipients,lastModifiedDateTime,isDraft',\n $orderby: 'lastModifiedDateTime desc',\n },\n ...(limit === undefined ? {} : { limit }),\n ...(ctx.args.bool('all') ? { all: true } : {}),\n });\n\n emit(ctx, messages, () => renderMessageList(messages));\n}\n\nasync function createDraft(ctx: CommandContext): Promise<void> {\n // Compose and check 'nothing to create' before reading the\n // signature file, so an empty draft surfaces the right error.\n const message = await composeMessage(ctx.args);\n\n if (Object.keys(message).length === 0) {\n throw new UsageError(\n 'Nothing to create. Provide at least --subject, --body or --to.',\n );\n }\n\n const signature = await resolveSignature(ctx.args, ctx.env);\n signMessage(message, signature, ctx.args);\n\n const spec = ctx.client.buildSpec('POST', '/me/messages', message);\n\n const created = await guardMutation(ctx, spec, () =>\n ctx.client.post<Message>('/me/messages', message),\n );\n\n if (created === undefined) return;\n\n emit(\n ctx,\n { ...created, signatureApplied: signature !== undefined },\n () => `Draft created: ${created.id}\\nSend it with: outlook draft send ${created.id}`,\n );\n}\n\nasync function updateDraft(ctx: CommandContext): Promise<void> {\n const id = ctx.args.requirePositional(1, '<draftId>');\n // Never sign on update: the draft was signed at create time, and a replaced\n // body would otherwise gain a second copy on every edit.\n if (signatureFlagRequested(ctx.args)) {\n throw new UsageError(\n 'draft update never adds a signature (it would duplicate the one added ' +\n 'at create time). Include it in --body yourself if you need it.',\n );\n }\n const message = await composeMessage(ctx.args);\n\n if (Object.keys(message).length === 0) {\n throw new UsageError(\n 'Nothing to update. Provide at least one of --subject, --body, --to, --cc, --bcc.',\n );\n }\n\n const path = `/me/messages/${encodeURIComponent(id)}`;\n const spec = ctx.client.buildSpec('PATCH', path, message);\n\n const updated = await guardMutation(ctx, spec, () =>\n ctx.client.patch<Message>(path, message),\n );\n\n if (updated === undefined) return;\n emit(ctx, updated, () => `Draft ${id} updated.`);\n}\n\nasync function sendDraft(ctx: CommandContext): Promise<void> {\n const id = ctx.args.requirePositional(1, '<draftId>');\n const path = `/me/messages/${encodeURIComponent(id)}/send`;\n const spec = ctx.client.buildSpec('POST', path, undefined);\n\n const sent = await guardMutation(ctx, spec, async () => {\n await ctx.client.post<void>(path);\n return true;\n });\n\n if (sent === undefined) return;\n emit(ctx, { sent: true, draftId: id }, () => `Draft ${id} sent.`);\n}\n\nexport const draftCommand: CommandSpec = {\n name: 'draft',\n summary: 'Create, update, list and send drafts',\n usage:\n 'outlook draft list [--limit N] [--all] [--json]\\n' +\n ' outlook draft create --subject <s> [--to <addr>...] [--body <text>] [--html] [--attach <path>...] [--dry-run]\\n' +\n ' outlook draft update <draftId> [--subject <s>] [--body <text>] [--to <addr>...] [--dry-run]\\n' +\n ' outlook draft send <draftId> [--dry-run]',\n mutating: true,\n\n async handler(ctx) {\n const sub = ctx.args.positionals[0];\n\n switch (sub) {\n case 'list':\n return listDrafts(ctx);\n case 'create':\n return createDraft(ctx);\n case 'update':\n return updateDraft(ctx);\n case 'send':\n return sendDraft(ctx);\n default:\n throw new UsageError(\n `Unknown draft subcommand${sub ? ` \"${sub}\"` : ''}. ` +\n `Valid subcommands: ${SUBCOMMANDS.join(', ')}.`,\n );\n }\n },\n};\n","/**\n * outlook mark-read / mark-unread / flag / unflag.\n *\n * All four are `PATCH /me/messages/{id}` (docs/02-write-endpoints.md §5).\n * Bodies are the exact shapes from that section:\n * isRead: { \"isRead\": true } / { \"isRead\": false }\n * flag: { \"flag\": { \"flagStatus\": \"flagged\" } }\n * { \"flag\": { \"flagStatus\": \"notFlagged\" } }\n * `flagStatus` is documented as exactly `notFlagged` | `flagged` | `complete`\n * (lowercase/camelCase, no capitalized variants) — see FlagStatus in types.ts.\n */\n\nimport type { CommandContext, CommandSpec } from '../command.js';\nimport { guardMutation, emit } from '../command.js';\nimport type { FlagStatus, Message } from '../types.js';\n\nfunction messagePath(id: string): string {\n return `/me/messages/${encodeURIComponent(id)}`;\n}\n\nasync function patchMessage(\n ctx: CommandContext,\n id: string,\n body: Record<string, unknown>,\n describe: (updated: Message) => string,\n): Promise<void> {\n const path = messagePath(id);\n const spec = ctx.client.buildSpec('PATCH', path, body);\n\n await guardMutation(ctx, spec, async () => {\n const updated = await ctx.client.patch<Message>(path, body);\n emit(ctx, { id, message: updated }, () => describe(updated));\n });\n}\n\nasync function setRead(ctx: CommandContext, isRead: boolean): Promise<void> {\n const id = ctx.args.requirePositional(0, '<id>');\n await patchMessage(ctx, id, { isRead }, () => `Marked ${id} as ${isRead ? 'read' : 'unread'}.`);\n}\n\nexport const markReadCommand: CommandSpec = {\n name: 'mark-read',\n summary: 'Mark a message as read.',\n usage: 'outlook mark-read <id> [--dry-run] [--json]',\n mutating: true,\n handler: (ctx) => setRead(ctx, true),\n};\n\nexport const markUnreadCommand: CommandSpec = {\n name: 'mark-unread',\n summary: 'Mark a message as unread.',\n usage: 'outlook mark-unread <id> [--dry-run] [--json]',\n mutating: true,\n handler: (ctx) => setRead(ctx, false),\n};\n\nasync function setFlag(ctx: CommandContext, flagStatus: FlagStatus): Promise<void> {\n const id = ctx.args.requirePositional(0, '<id>');\n await patchMessage(\n ctx,\n id,\n { flag: { flagStatus } },\n () => `Set flag on ${id} to \"${flagStatus}\".`,\n );\n}\n\nexport const flagCommand: CommandSpec = {\n name: 'flag',\n summary: 'Flag a message for follow-up.',\n usage: 'outlook flag <id> [--dry-run] [--json]',\n mutating: true,\n handler: (ctx) => setFlag(ctx, 'flagged'),\n};\n\nexport const unflagCommand: CommandSpec = {\n name: 'unflag',\n summary: 'Clear a message\\'s follow-up flag.',\n usage: 'outlook unflag <id> [--dry-run] [--json]',\n mutating: true,\n handler: (ctx) => setFlag(ctx, 'notFlagged'),\n};\n","/**\n * `outlook folders` — list and create mail folders.\n *\n * Subcommand dispatch on positional 0 (`list` is the default when absent):\n * outlook folders [list] [--parent <name|id>] [--all] [--json]\n * outlook folders create --name <text> [--dry-run] [--json]\n *\n * LIST: `GET /me/mailFolders` (docs/01-read-endpoints.md §1) returns only\n * **root-level** child folders — it does not recurse (§2, line 102: \"To\n * enumerate all folders, each child folder's `childFolders` must be\n * traversed separately\"). That `childFolders` collection is a real,\n * documented nested resource (confirmed by the attachments path pattern in\n * §7: `GET /me/mailFolders/{id}/childFolders/{id}/.../attachments/{id}`), so\n * `--parent <name|id>` here maps to `GET /me/mailFolders/{parent}/childFolders`\n * rather than an invented query parameter. Well-known folder names are\n * lowercase literals (docs/01 §2); an opaque folder id is passed through\n * unchanged (mirrors `move.ts`'s `resolveDestinationId`).\n *\n * CREATE: `POST /me/mailFolders` (docs/02-write-endpoints.md §7). Verbatim\n * from that doc: \"displayName and isHidden are the only writable property\n * for a mailFolder object\" — `parentFolderId` is explicitly **not** accepted\n * on create (\"folders are always created at root\"). So `create`\n * deliberately has no `--parent` support: passing one is a clean UsageError\n * rather than a silently-ignored, misleading flag. Per docs/02 §8 this write\n * is **UNSAFE to retry** (\"no documented uniqueness constraint on\n * displayName; retry creates a duplicate folder\"), so — like every mutation\n * in this CLI — it is wrapped in `guardMutation`.\n */\n\nimport { emit, guardMutation, type CommandContext, type CommandSpec } from '../command.js';\nimport { collectItems } from '../paginate.js';\nimport { renderFolders } from '../output.js';\nimport { isWellKnownFolder, type MailFolder } from '../types.js';\nimport { UsageError } from '../errors.js';\n\n/** Well-known names are documented as lowercase literals; a raw folder id is opaque and case-sensitive. */\nfunction resolveFolderId(folder: string): string {\n return isWellKnownFolder(folder) ? folder.toLowerCase() : folder;\n}\n\nfunction foldersListPath(parent: string | undefined): string {\n if (parent === undefined) return '/me/mailFolders';\n return `/me/mailFolders/${encodeURIComponent(resolveFolderId(parent))}/childFolders`;\n}\n\nasync function listHandler(ctx: CommandContext): Promise<void> {\n const parent = ctx.args.str('parent');\n const path = foldersListPath(parent);\n const opts = ctx.args.bool('all') ? { all: true } : {};\n\n const folders = await collectItems<MailFolder>(ctx.client, path, opts);\n\n emit(ctx, folders, () => renderFolders(folders));\n}\n\nasync function createHandler(ctx: CommandContext): Promise<void> {\n if (ctx.args.has('parent')) {\n throw new UsageError(\n 'outlook folders create does not accept --parent: Microsoft Graph only ' +\n 'creates mail folders at the mailbox root (docs/02-write-endpoints.md §7 — ' +\n '\"folders are always created at root\"; parentFolderId is not an accepted ' +\n 'request parameter on POST /me/mailFolders).',\n );\n }\n\n const name = ctx.args.require('name');\n const body = { displayName: name };\n const path = '/me/mailFolders';\n const spec = ctx.client.buildSpec('POST', path, body);\n\n const created = await guardMutation(ctx, spec, async () => ctx.client.post<MailFolder>(path, body));\n\n if (created === undefined) return; // --dry-run already reported\n\n emit(ctx, created, () => `Created folder \"${created.displayName}\" (id: ${created.id})`);\n}\n\nasync function foldersHandler(ctx: CommandContext): Promise<void> {\n const sub = ctx.args.positionals[0] ?? 'list';\n\n switch (sub) {\n case 'list':\n return listHandler(ctx);\n case 'create':\n return createHandler(ctx);\n default:\n throw new UsageError(`Unknown folders subcommand \"${sub}\". Expected \"list\" or \"create\".`);\n }\n}\n\nexport const foldersCommand: CommandSpec = {\n name: 'folders',\n summary: 'List or create mail folders',\n usage:\n 'outlook folders [list] [--parent <name|id>] [--all] [--json]\\n' +\n ' outlook folders create --name <text> [--dry-run] [--json]',\n mutating: true,\n handler: foldersHandler,\n};\n","/**\n * `outlook get` — GET /me/messages/{id} (docs/01-read-endpoints.md §1, §6.4).\n *\n * Read-only: `mutating: false`. Nothing here is irreversible, so there is no\n * `guardMutation` wrapper — that chokepoint exists for state-changing calls\n * only (see command.ts).\n *\n * The message id is positional, not a flag (`requirePositional` gives a\n * clean UsageError instead of an undefined-id crash). Graph message ids are\n * opaque strings (docs/01 §6.4 example: \"AAMkADhMGAAA=\") that can contain\n * characters unsafe to splice unencoded into a URL path segment, so the id\n * is percent-encoded before being joined onto `/me/messages/`.\n *\n * `body` is returned in HTML by default (docs/01 §6.2) unless a caller sends\n * `Prefer: outlook.body-content-type=\"text\"` — this command never sends that\n * header. Instead `--html` is forwarded straight into `renderMessage`'s\n * `opts.html` (src/output.ts), which already knows how to choose between the\n * raw HTML and a plain-text conversion of whatever `contentType` came back.\n *\n * docs/01 §6.1/§7 documents `attachments` only as a *separate* collection\n * endpoint (`GET /me/messages/{id}/attachments`) — no `$select`/`$expand`\n * combination that inlines attachment metadata into a message-get response\n * is documented anywhere in docs/01. So there is deliberately no\n * `--attachments` flag here; adding one would invent an unverified query\n * shape.\n */\n\nimport { emit, type CommandContext, type CommandSpec } from '../command.js';\nimport { renderMessage } from '../output.js';\nimport type { Message } from '../types.js';\n\nasync function getHandler(ctx: CommandContext): Promise<void> {\n const id = ctx.args.requirePositional(0, '<messageId>');\n const path = `/me/messages/${encodeURIComponent(id)}`;\n\n const message = await ctx.client.get<Message>(path);\n\n emit(ctx, message, () => renderMessage(message, { html: ctx.args.bool('html') }));\n}\n\nexport const getCommand: CommandSpec = {\n name: 'get',\n summary: 'Fetch and display a single message',\n usage: 'outlook get <messageId> [--html] [--json]',\n mutating: false,\n handler: getHandler,\n};\n","/**\n * `outlook list` — list messages in a folder, newest first.\n *\n * Endpoint: `GET /me/mailFolders/{id}/messages` (docs/01-read-endpoints.md §2\n * table row \"List messages in a specific folder\"). `--folder` accepts either\n * a well-known folder name (validated via `isWellKnownFolder`) or an opaque\n * folder id — docs/01 §2 confirms well-known names are \"usable in place of a\n * folder `{id}`, e.g. `GET /me/mailFolders/inbox/messages`. Work regardless\n * of the mailbox's display-language locale.\" An unrecognized `--folder`\n * value is treated as a raw folder id and percent-encoded onto the same\n * path shape.\n *\n * Read-only: `mutating: false`, no `guardMutation` (see get.ts — that\n * chokepoint is reserved for state-changing commands).\n *\n * Sort: `$orderby=receivedDateTime desc` alone — newest first (docs/01 §3.3).\n * `--unread` adds `$filter=isRead eq false` as its own independent query\n * param rather than folding it together with `$orderby` into one compound\n * expression: docs/01 §3.4 documents an exact, quotable constraint\n * (`InefficientFilter`: \"The restriction or sort order is too complex for\n * this operation\") that fires when `$orderby` properties don't also appear\n * in `$filter`, in the same order, before any non-`$orderby` properties.\n * Keeping `isRead` out of `$orderby` and `receivedDateTime` out of `$filter`\n * sidesteps that constraint entirely, and docs/01 §3.2 confirms\n * `$filter=isRead eq false` alone is a working example on its own.\n *\n * `$select` is kept small for list output (docs/01 §3.1 recommends\n * `$select` for latency) — just enough fields for `renderMessageList`.\n *\n * Paging: default is a single page sized by `--limit` (default 25; docs/01\n * §3.5 documents the messages `$top` range as 1-1000, so `--limit` is\n * validated against that same range). `--all` follows every\n * `@odata.nextLink` via `collectItems`'s own pagination loop instead.\n */\n\nimport { emit, type CommandContext, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport { renderMessageList } from '../output.js';\nimport { collectItems } from '../paginate.js';\nimport { isWellKnownFolder, type Message } from '../types.js';\n\nconst SELECT = 'subject,from,receivedDateTime,isRead,hasAttachments,bodyPreview';\nconst ORDERBY = 'receivedDateTime desc';\nconst MAX_TOP = 1000;\n\nfunction folderPath(folder: string): string {\n const segment = isWellKnownFolder(folder) ? folder.toLowerCase() : encodeURIComponent(folder);\n return `/me/mailFolders/${segment}/messages`;\n}\n\nfunction readLimit(ctx: CommandContext): number {\n if (!ctx.args.has('limit')) return 25;\n const limit = ctx.args.num('limit');\n if (limit === undefined || !Number.isInteger(limit) || limit < 1 || limit > MAX_TOP) {\n throw new UsageError(`--limit must be an integer between 1 and ${MAX_TOP}`);\n }\n return limit;\n}\n\nasync function listHandler(ctx: CommandContext): Promise<void> {\n const folder = ctx.args.str('folder', 'inbox') ?? 'inbox';\n const limit = readLimit(ctx);\n const all = ctx.args.bool('all');\n const unread = ctx.args.bool('unread');\n\n const query: Record<string, unknown> = {\n $select: SELECT,\n $orderby: ORDERBY,\n $top: limit,\n };\n if (unread) query.$filter = 'isRead eq false';\n\n const messages = await collectItems<Message>(ctx.client, folderPath(folder), {\n query,\n limit,\n all,\n });\n\n emit(ctx, messages, () => renderMessageList(messages));\n}\n\nexport const listCommand: CommandSpec = {\n name: 'list',\n summary: 'List messages in a folder, newest first',\n usage: 'outlook list [--folder <name|id>] [--limit <n>] [--all] [--unread] [--json]',\n mutating: false,\n handler: listHandler,\n};\n","/**\n * `outlook me` — GET /me (docs/01-read-endpoints.md §1).\n *\n * The smallest command in the CLI: fetches the signed-in user's profile and\n * renders it via renderProfile. docs/01 §1 calls `GET /me` out explicitly —\n * \"This CLI should treat `GET /me` as its identity-check endpoint\" — so this\n * command doubles as the natural \"is my auth working?\" smoke test: run it\n * with no arguments and a clean profile (or a clean error) tells you whether\n * the cached token is good.\n *\n * That means an auth failure here must never be swallowed. There is no\n * try/catch in this handler — a GraphError (e.g. InvalidAuthenticationToken)\n * or any other rejection from ctx.client.get propagates straight out to the\n * caller with the real Graph error code/message intact (see errors.ts),\n * which is exactly what makes this command useful as a smoke test.\n *\n * Read-only: `mutating: false`, no guardMutation — see command.ts.\n */\n\nimport { emit, type CommandContext, type CommandSpec } from '../command.js';\nimport { renderProfile } from '../output.js';\nimport type { UserProfile } from '../types.js';\n\n/** Exactly the fields UserProfile (types.ts) declares — nothing more. */\nconst SELECT_FIELDS = 'id,displayName,mail,userPrincipalName,jobTitle';\n\nasync function meHandler(ctx: CommandContext): Promise<void> {\n const profile = await ctx.client.get<UserProfile>('/me', { $select: SELECT_FIELDS });\n\n emit(ctx, profile, () => renderProfile(profile));\n}\n\nexport const meCommand: CommandSpec = {\n name: 'me',\n summary: \"Show the signed-in user's profile — also a quick auth smoke-test\",\n usage: 'outlook me [--json]',\n mutating: false,\n handler: meHandler,\n};\n","/**\n * outlook delete / move / purge.\n *\n * SAFETY (docs/02-write-endpoints.md §4): Microsoft's own docs confirm that\n * `POST /me/messages/{id}/move` -> {\"destinationId\":\"deleteditems\"} lands the\n * message in the visible, user-browsable Deleted Items folder — recoverable\n * in the ordinary Outlook sense. The docs are silent on whether a raw\n * `DELETE /me/messages/{id}` is recoverable at all. An undocumented\n * irreversible-or-not operation is treated as irreversible by default here.\n *\n * `delete` therefore performs the MOVE, never the raw DELETE. Only `purge`\n * issues the raw DELETE, and only when the caller passes --yes.\n *\n * IMPORTANT: per §4's own worked example, a successful move returns a NEW\n * message id — the id used in the request no longer resolves afterward.\n * Callers must treat the response's id as the message's identity going\n * forward, not the id they passed in.\n */\n\nimport type { CommandContext, CommandSpec } from '../command.js';\nimport { guardMutation, emit } from '../command.js';\nimport { isWellKnownFolder } from '../types.js';\nimport type { Message } from '../types.js';\nimport { UsageError } from '../errors.js';\n\nconst DELETED_ITEMS = 'deleteditems';\n\nfunction messagePath(id: string): string {\n return `/me/messages/${encodeURIComponent(id)}`;\n}\n\n/** Well-known names are documented as lowercase literals; a raw folder id is opaque and case-sensitive. */\nfunction resolveDestinationId(folder: string): string {\n return isWellKnownFolder(folder) ? folder.toLowerCase() : folder;\n}\n\nasync function moveMessage(ctx: CommandContext, id: string, destinationId: string): Promise<void> {\n const path = `${messagePath(id)}/move`;\n const body = { destinationId };\n const spec = ctx.client.buildSpec('POST', path, body);\n\n await guardMutation(ctx, spec, async () => {\n const moved = await ctx.client.post<Message>(path, body);\n emit(\n ctx,\n { movedFrom: id, destinationId, message: moved },\n () =>\n `Moved message ${id} -> ${destinationId}. New id: ${moved.id} ` +\n `(the old id no longer resolves — use the new id for anything further).`,\n );\n });\n}\n\nasync function deleteHandler(ctx: CommandContext): Promise<void> {\n const id = ctx.args.requirePositional(0, '<id>');\n await moveMessage(ctx, id, DELETED_ITEMS);\n}\n\nexport const deleteCommand: CommandSpec = {\n name: 'delete',\n summary: 'Move a message to Deleted Items (recoverable). The safe default \"delete\".',\n usage: 'outlook delete <id> [--dry-run] [--json]',\n mutating: true,\n handler: deleteHandler,\n};\n\nasync function moveHandler(ctx: CommandContext): Promise<void> {\n const id = ctx.args.requirePositional(0, '<id>');\n const folder = ctx.args.require('folder');\n await moveMessage(ctx, id, resolveDestinationId(folder));\n}\n\nexport const moveCommand: CommandSpec = {\n name: 'move',\n summary: 'Move a message to another folder (well-known name or folder id).',\n usage: 'outlook move <id> --folder <name|id> [--dry-run] [--json]',\n mutating: true,\n handler: moveHandler,\n};\n\nasync function purgeHandler(ctx: CommandContext): Promise<void> {\n const id = ctx.args.requirePositional(0, '<id>');\n\n if (!ctx.args.bool('yes')) {\n throw new UsageError(\n `outlook purge issues a raw DELETE /me/messages/${id}. Microsoft's docs ` +\n `never state whether this is recoverable — it is treated as permanent. ` +\n `Pass --yes to confirm you understand this, or run \\`outlook delete ${id}\\` ` +\n `instead, which moves the message to Deleted Items and IS recoverable.`,\n );\n }\n\n const path = messagePath(id);\n const spec = ctx.client.buildSpec('DELETE', path);\n\n await guardMutation(ctx, spec, async () => {\n await ctx.client.del(path);\n emit(\n ctx,\n { purged: true, id },\n () =>\n `Purged message ${id} via raw DELETE. Recoverability is not documented ` +\n `by Microsoft — treat this as permanent.`,\n );\n });\n}\n\nexport const purgeCommand: CommandSpec = {\n name: 'purge',\n summary: 'Permanently delete a message via raw DELETE. Requires --yes.',\n usage: 'outlook purge <id> --yes [--dry-run] [--json]',\n mutating: true,\n handler: purgeHandler,\n};\n","/**\n * Three-step reply/replyAll/forward flow used when an HTML signature applies.\n *\n * The one-shot `/reply` action only accepts a `comment` field (plain text),\n * so it cannot carry an HTML signature. When the resolved signature has an\n * HTML form we fall back to:\n *\n * 1. POST /me/messages/{id}/createReply → draft (Exchange adds quoted body)\n * 2. PATCH /me/messages/{draftId} → insert user text + signature\n * 3. POST /me/messages/{draftId}/send → send\n *\n * Threading headers (In-Reply-To, References) are set by step 1 and survive\n * the PATCH, so conversation threading is preserved.\n *\n * Signature trust boundary: sig.html is operator-supplied (--signature <path>\n * or OUTLOOK_SIGNATURE_HTML_FILE) and is treated as trusted content, the same\n * boundary documented in signature.ts and README.md §Signature files.\n * Never point these variables at world-writable or user-uploaded paths.\n *\n * Atomicity: the flow is NOT atomic. On PATCH or send failure we attempt to\n * DELETE the draft; if that also fails, the user is instructed to run\n * `outlook draft list` to locate and delete it manually.\n *\n * docs/02 §8: POST is never auto-retried; PATCH/DELETE use the normal retry\n * logic already in GraphClient.\n */\n\nimport type { GraphClient } from '../client.js';\nimport { OutlookCliError } from '../errors.js';\nimport {\n TEXT_DELIMITER,\n type Signature,\n} from '../signature.js';\nimport type { ItemBody, Message } from '../types.js';\n\nexport type CreateAction = 'createReply' | 'createReplyAll' | 'createForward';\n\nexport interface ReplyDraftOptions {\n messageId: string;\n action: CreateAction;\n /** User-supplied body text (may be empty string). */\n userText: string;\n signature: Signature;\n /** For forward: required recipients. */\n toRecipients?: Array<{ emailAddress: { address: string; name?: string } }>;\n}\n\nexport interface ReplyDraftSpecs {\n createSpec: ReturnType<GraphClient['buildSpec']>;\n patchSpec: ReturnType<GraphClient['buildSpec']>;\n sendSpec: ReturnType<GraphClient['buildSpec']>;\n}\n\n/**\n * Build the three RequestSpecs for --dry-run display.\n *\n * The PATCH body cannot be fully materialised at dry-run time (we don't know\n * the draft id or its Exchange-generated body), so we produce a representative\n * placeholder that shows the shape of what will be sent.\n */\nexport function buildReplyDraftSpecs(\n client: GraphClient,\n opts: ReplyDraftOptions,\n): ReplyDraftSpecs {\n const basePath = `/me/messages/${encodeURIComponent(opts.messageId)}`;\n\n const createBody: Record<string, unknown> = {};\n if (opts.toRecipients) createBody['toRecipients'] = opts.toRecipients;\n\n const createSpec = client.buildSpec('POST', `${basePath}/${opts.action}`, createBody);\n\n // Representative patch body — actual content depends on the draft Exchange returns.\n const patchPreview = buildPatchBody(\n { contentType: 'html', content: '<html><body><!-- Exchange quoted body --></body></html>' },\n opts.userText,\n opts.signature,\n );\n const patchSpec = client.buildSpec('PATCH', '/me/messages/{draftId}', patchPreview);\n\n const sendSpec = client.buildSpec('POST', '/me/messages/{draftId}/send', undefined);\n\n return { createSpec, patchSpec, sendSpec };\n}\n\n/**\n * Execute the three-step flow, cleaning up the draft on failure.\n *\n * Returns the draft id so callers can surface it in the success output.\n */\nexport async function executeReplyDraft(\n client: GraphClient,\n opts: ReplyDraftOptions,\n): Promise<string> {\n const basePath = `/me/messages/${encodeURIComponent(opts.messageId)}`;\n\n // Step 1: create draft (Exchange fills in quoted body + threading headers).\n const createBody: Record<string, unknown> = {};\n if (opts.toRecipients) createBody['toRecipients'] = opts.toRecipients;\n\n const draft = await client.post<Message>(\n `${basePath}/${opts.action}`,\n createBody,\n );\n const draftId = draft?.id;\n if (!draftId) {\n throw new OutlookCliError(\n `${opts.action} did not return a draft id. ` +\n 'The message may not have been sent.',\n );\n }\n\n // Steps 2+3: patch then send, deleting the draft on any failure.\n try {\n // Step 2: read back the draft body Exchange generated, then patch.\n const draftFull = await client.get<Message>(\n `/me/messages/${encodeURIComponent(draftId)}`,\n { $select: 'id,body' },\n );\n if (!draftFull?.body) {\n throw new OutlookCliError(\n 'Exchange returned a draft with no body. Cannot patch reply.',\n );\n }\n const draftBody: ItemBody = draftFull.body;\n const patchBody = buildPatchBody(draftBody, opts.userText, opts.signature);\n await client.patch<unknown>(\n `/me/messages/${encodeURIComponent(draftId)}`,\n patchBody,\n );\n\n // Step 3: send the patched draft.\n await client.post<void>(\n `/me/messages/${encodeURIComponent(draftId)}/send`,\n undefined,\n );\n } catch (stepErr) {\n // Attempt cleanup — best effort.\n let cleanupErr: unknown;\n try {\n await client.del(`/me/messages/${encodeURIComponent(draftId)}`);\n } catch (e) {\n cleanupErr = e;\n }\n\n const base =\n stepErr instanceof Error ? stepErr.message : String(stepErr);\n\n if (cleanupErr !== undefined) {\n const cleanMsg =\n cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr);\n throw new OutlookCliError(\n `Failed to send reply (${base}). ` +\n `Cleanup also failed (${cleanMsg}). ` +\n 'A draft was left behind (ORPHAN) — run `outlook draft list` to find and delete it.',\n );\n }\n\n throw new OutlookCliError(\n `Failed to send reply (${base}). ` +\n 'The draft was deleted. No message was sent.',\n );\n }\n\n return draftId;\n}\n\n// ---------------------------------------------------------------------------\n// Body-insertion helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Produce the PATCH body that inserts `userText` + signature above the\n * Exchange-generated quoted block, in the draft's own content type.\n */\nfunction buildPatchBody(\n draftBody: ItemBody,\n userText: string,\n sig: Signature,\n): { body: ItemBody } {\n const isHtml = draftBody.contentType.toLowerCase() === 'html';\n const newBody = isHtml\n ? insertHtml(draftBody.content, userText, sig)\n : insertText(draftBody.content, userText, sig);\n return { body: { contentType: draftBody.contentType, content: newBody } };\n}\n\n/**\n * Insert user text and HTML signature above the Exchange quote in an HTML body.\n *\n * Exchange wraps the quoted message in a <div id=\"divRplyFwdMsg\"> block. We\n * look for that marker and inject above it; if not found we prepend to <body>\n * (or to the whole content when there is no <body> tag).\n */\nfunction insertHtml(draftContent: string, userText: string, sig: Signature): string {\n const textHtml = escapeHtml(userText.trimEnd()).replace(/\\r?\\n/g, '<br>');\n const sigHtml =\n sig.html?.trim() ??\n escapeHtml((sig.text ?? '').trimEnd()).replace(/\\r?\\n/g, '<br>');\n\n const insertion =\n `<div>${textHtml}</div>` +\n `<br><div class=\"outlook-cli-signature\">${sigHtml}</div><br>`;\n\n // Try to place before the Exchange quote div.\n const quoteMatch = draftContent.match(/<div\\s+id=[\"']divRplyFwdMsg[\"']/i);\n if (quoteMatch?.index !== undefined) {\n return (\n draftContent.slice(0, quoteMatch.index) +\n insertion +\n draftContent.slice(quoteMatch.index)\n );\n }\n\n // Fall back: inject at the start of <body>.\n const bodyMatch = [...draftContent.matchAll(/<body[^>]*>/gi)];\n const lastBody = bodyMatch[bodyMatch.length - 1];\n if (lastBody?.index !== undefined) {\n const afterBody = lastBody.index + lastBody[0].length;\n return (\n draftContent.slice(0, afterBody) +\n insertion +\n draftContent.slice(afterBody)\n );\n }\n\n // No <body> tag — prepend.\n return insertion + draftContent;\n}\n\n/**\n * Insert user text and text signature above the Exchange plain-text quote.\n *\n * Exchange delimits the quote with \"-----Original Message-----\" (or a locale\n * variant). We look for that marker and insert above it; if not found we\n * prepend the new content.\n */\nfunction insertText(draftContent: string, userText: string, sig: Signature): string {\n if (sig.text === undefined) {\n // HTML-only signature in a text draft: fall back to escaping the HTML.\n const stripped = (sig.html ?? '').replace(/<[^>]*>/g, '').trim();\n return buildTextInsertion(draftContent, userText, stripped);\n }\n return buildTextInsertion(draftContent, userText, sig.text.trimEnd());\n}\n\nfunction buildTextInsertion(\n draftContent: string,\n userText: string,\n sigText: string,\n): string {\n const head = userText.trimEnd();\n const sigBlock = `${TEXT_DELIMITER}\\n${sigText}`;\n const newContent = head === '' ? sigBlock : `${head}\\n\\n${sigBlock}`;\n\n // Look for Exchange's plain-text quote separator.\n // Use a structural pattern (---…text…---) rather than English \"Original Message\"\n // so localized variants (German, French, Japanese, etc.) are matched too.\n const sepMatch = draftContent.match(/^-{3,}[^-\\r\\n][^\\r\\n]*-{3,}/im);\n if (sepMatch?.index !== undefined) {\n return `${newContent}\\n\\n${draftContent.slice(sepMatch.index)}`;\n }\n\n // No quote found — prepend.\n if (draftContent.trim() === '') return newContent;\n return `${newContent}\\n\\n${draftContent}`;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n","/**\n * `outlook reply` / `reply-all` / `forward`.\n *\n * Two paths, chosen by whether the resolved signature has an HTML form:\n *\n * TEXT-ONLY (or no signature):\n * POST /me/messages/{id}/reply|replyAll|forward { comment }\n * Single request; existing behaviour unchanged.\n *\n * HTML SIGNATURE:\n * 1. POST /me/messages/{id}/createReply|createReplyAll|createForward\n * → Exchange creates a draft with the quoted body and sets threading headers.\n * 2. GET the draft, insert user text + signature above the Exchange quote,\n * PATCH /me/messages/{draftId} { body }\n * 3. POST /me/messages/{draftId}/send\n *\n * On PATCH or send failure the draft is deleted and the error reported.\n * If the delete also fails, the draft id is surfaced so the user can clean up.\n * --dry-run shows all three requests without touching the network.\n *\n * Why the split rather than always using the 3-step path?\n * The one-shot action is one request, atomic, and battle-tested. For users\n * with only a plain-text signature there is no reason to trade that in for a\n * non-atomic three-request flow. The split keeps the fast path fast and\n * limits the new surface to where it is actually needed.\n *\n * docs/02 §2: replyAll documents only `comment`; the surrounding prose implies\n * a `message` object may also be accepted but is unverified. The three-step\n * path uses createReplyAll (a separate action) which is documented to return a\n * draft, so we avoid the ambiguity entirely.\n */\n\nimport { emit, guardMutation, type CommandContext, type CommandSpec } from '../command.js';\nimport { renderRequest } from '../dryRun.js';\nimport { UsageError } from '../errors.js';\nimport { dryRunVerdict, enforcePolicy, renderVerdict } from '../policyGuard.js';\nimport { appendTextSignature, resolveSignature } from '../signature.js';\nimport { describeRecipients, recipientsFromArgs } from './compose.js';\nimport {\n buildReplyDraftSpecs,\n executeReplyDraft,\n type CreateAction,\n} from './replyDraft.js';\n\ntype ReplyKind = 'reply' | 'replyAll' | 'forward';\n\nconst ACTION_PATH: Record<ReplyKind, string> = {\n reply: 'reply',\n replyAll: 'replyAll',\n forward: 'forward',\n};\n\nconst CREATE_ACTION: Record<ReplyKind, CreateAction> = {\n reply: 'createReply',\n replyAll: 'createReplyAll',\n forward: 'createForward',\n};\n\nasync function runReplyAction(\n ctx: CommandContext,\n kind: ReplyKind,\n label: string,\n): Promise<void> {\n const messageId = ctx.args.requirePositional(0, '<messageId>');\n const userText = ctx.args.str('body') ?? '';\n const signature = await resolveSignature(ctx.args, ctx.env);\n\n // Forward always needs recipients regardless of path.\n const toRecipients = kind === 'forward' ? recipientsFromArgs(ctx.args, 'to') : undefined;\n if (kind === 'forward' && (!toRecipients || toRecipients.length === 0)) {\n throw new UsageError(\n 'forward requires at least one recipient. Use --to <address>.',\n );\n }\n\n // Choose path: HTML signature → 3-step draft flow; otherwise one-shot comment.\n const useHtmlFlow = signature !== undefined && signature.html !== undefined;\n\n if (useHtmlFlow) {\n await runHtmlFlow(ctx, kind, label, messageId, userText, signature!, toRecipients);\n return;\n }\n\n // -------------------------------------------------------------------------\n // One-shot comment path (text-only or no signature).\n // -------------------------------------------------------------------------\n const comment =\n signature === undefined ? userText : appendTextSignature(userText, signature);\n\n const payload: Record<string, unknown> = { comment };\n if (toRecipients) payload['toRecipients'] = toRecipients;\n\n const path = `/me/messages/${encodeURIComponent(messageId)}/${ACTION_PATH[kind]}`;\n const spec = ctx.client.buildSpec('POST', path, payload);\n\n const done = await guardMutation(ctx, spec, async () => {\n await ctx.client.post<void>(path, payload);\n return true;\n });\n\n if (done === undefined) return; // --dry-run\n\n emit(\n ctx,\n {\n action: kind,\n messageId,\n sent: true,\n signatureApplied: signature !== undefined,\n htmlSignature: false,\n },\n () =>\n `${label} sent for message ${messageId}` +\n (toRecipients ? ` to ${describeRecipients(toRecipients)}` : ''),\n );\n}\n\n/**\n * Three-step HTML-signature flow.\n * --dry-run renders all three requests and returns without touching the network.\n */\nasync function runHtmlFlow(\n ctx: CommandContext,\n kind: ReplyKind,\n label: string,\n messageId: string,\n userText: string,\n signature: NonNullable<Awaited<ReturnType<typeof resolveSignature>>>,\n toRecipients: ReturnType<typeof recipientsFromArgs> | undefined,\n): Promise<void> {\n const specs = buildReplyDraftSpecs(ctx.client, {\n messageId,\n action: CREATE_ACTION[kind],\n userText,\n signature,\n toRecipients,\n });\n\n if (ctx.dryRun) {\n ctx.out('DRY RUN — nothing was sent. The three requests below are what would go out:');\n ctx.out('');\n ctx.out('--- Step 1: create draft ---');\n ctx.out(renderRequest(specs.createSpec));\n ctx.out('');\n ctx.out('--- Step 2: patch body (representative; actual body depends on Exchange draft) ---');\n ctx.out(renderRequest(specs.patchSpec));\n ctx.out('');\n ctx.out('--- Step 3: send draft ---');\n ctx.out(renderRequest(specs.sendSpec));\n const verdict = await dryRunVerdict(ctx, specs.sendSpec);\n if (verdict !== undefined) {\n ctx.out('');\n ctx.out(renderVerdict(verdict));\n }\n return;\n }\n\n // Enforce policy for each of the three steps before any network call.\n await enforcePolicy(ctx, specs.createSpec);\n await enforcePolicy(ctx, specs.patchSpec);\n await enforcePolicy(ctx, specs.sendSpec);\n\n const draftId = await executeReplyDraft(ctx.client, {\n messageId,\n action: CREATE_ACTION[kind],\n userText,\n signature,\n toRecipients,\n });\n\n emit(\n ctx,\n {\n action: kind,\n messageId,\n sent: true,\n signatureApplied: true,\n htmlSignature: true,\n draftId,\n },\n () =>\n `${label} sent for message ${messageId}` +\n (toRecipients ? ` to ${describeRecipients(toRecipients)}` : ''),\n );\n}\n\nexport const replyCommand: CommandSpec = {\n name: 'reply',\n summary: 'Reply to the sender of a message',\n usage:\n 'outlook reply <messageId> [--body <text>] ' +\n '[--signature <path> | --no-signature] [--dry-run] [--json]',\n mutating: true,\n handler: (ctx) => runReplyAction(ctx, 'reply', 'Reply'),\n};\n\nexport const replyAllCommand: CommandSpec = {\n name: 'reply-all',\n summary: 'Reply to all recipients of a message',\n usage:\n 'outlook reply-all <messageId> [--body <text>] ' +\n '[--signature <path> | --no-signature] [--dry-run] [--json]',\n mutating: true,\n handler: (ctx) => runReplyAction(ctx, 'replyAll', 'Reply-all'),\n};\n\nexport const forwardCommand: CommandSpec = {\n name: 'forward',\n summary: 'Forward a message to other recipients',\n usage:\n 'outlook forward <messageId> --to <addr> [--to <addr>...] ' +\n '[--body <text>] [--signature <path> | --no-signature] [--dry-run] [--json]',\n mutating: true,\n handler: (ctx) => runReplyAction(ctx, 'forward', 'Forward'),\n};\n","/**\n * `outlook rules` — list and create inbox message rules.\n *\n * Graph endpoint (list): `GET /me/mailFolders/inbox/messageRules`\n * Graph endpoint (create): `POST /me/mailFolders/inbox/messageRules`\n * (see https://learn.microsoft.com/en-us/graph/api/mailfolder-list-messagerules)\n * (see https://learn.microsoft.com/en-us/graph/api/mailfolder-post-messagerules)\n *\n * Each messageRule has: displayName, sequence, isEnabled, isReadOnly,\n * conditions, actions, exceptions. `list` is read-only — no guardMutation\n * needed, no --dry-run. `create` is mutating: it creates a new server-side\n * inbox rule via POST and goes through `guardMutation` for --dry-run safety.\n *\n * Subcommand dispatch on positional 0 (`list` is the default):\n * outlook rules [list] [--json]\n * outlook rules create --name <text> --folder <id>\n * [--from <addr>...] [--sender-contains <domain>...]\n * [--mark-read] [--stop-processing] [--enabled]\n * [--dry-run] [--json]\n *\n * SAFETY: `create` is UNSAFE to retry — Graph applies no uniqueness constraint\n * on rule displayName; a blindly-retried POST creates a duplicate. Wrapped in\n * `guardMutation` and never auto-retried (POST is not in RETRYABLE_METHODS).\n *\n * Scope requirement: `MailboxSettings.ReadWrite` must be consented at login.\n * `MailboxSettings.Read` is sufficient for `list` but not for `create`.\n */\n\nimport { emit, guardMutation, type CommandContext, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport type { GraphCollection } from '../types.js';\n\n/* ---------- Graph response types (subset we render) ---------- */\n\ninterface RuleEmailAddress {\n emailAddress?: { address?: string; name?: string };\n}\n\n/** Conditions or exceptions on a message rule. */\nexport interface RuleConditions {\n fromAddresses?: RuleEmailAddress[];\n sentToAddresses?: RuleEmailAddress[];\n subjectContains?: string[];\n bodyContains?: string[];\n headerContains?: string[];\n senderContains?: string[];\n recipientContains?: string[];\n bodyOrSubjectContains?: string[];\n hasAttachments?: boolean;\n importance?: string;\n isAutomatic?: boolean;\n [key: string]: unknown;\n}\n\n/** Actions performed when a rule matches. */\nexport interface RuleActions {\n moveToFolder?: string;\n copyToFolder?: string;\n delete?: boolean;\n permanentDelete?: boolean;\n markAsRead?: boolean;\n markImportance?: string;\n forwardTo?: RuleEmailAddress[];\n forwardAsAttachmentTo?: RuleEmailAddress[];\n redirectTo?: RuleEmailAddress[];\n stopProcessingRules?: boolean;\n [key: string]: unknown;\n}\n\nexport interface MessageRule {\n id?: string;\n displayName?: string;\n sequence?: number;\n isEnabled?: boolean;\n isReadOnly?: boolean;\n conditions?: RuleConditions;\n actions?: RuleActions;\n exceptions?: RuleConditions;\n}\n\n/* ---------- Human-readable summarisers ---------- */\n\nfunction addrList(addrs?: RuleEmailAddress[]): string {\n if (!addrs || addrs.length === 0) return '';\n return addrs\n .map((a) => a.emailAddress?.address ?? a.emailAddress?.name ?? '?')\n .join(', ');\n}\n\n/** Short human string describing which messages match. */\nexport function summariseConditions(c?: RuleConditions): string {\n if (!c) return '(any)';\n const parts: string[] = [];\n\n const from = addrList(c.fromAddresses);\n if (from) parts.push(`from: ${from}`);\n\n const to = addrList(c.sentToAddresses);\n if (to) parts.push(`to: ${to}`);\n\n if (c.subjectContains?.length) parts.push(`subject contains: ${c.subjectContains.join(', ')}`);\n if (c.bodyContains?.length) parts.push(`body contains: ${c.bodyContains.join(', ')}`);\n if (c.senderContains?.length) parts.push(`sender contains: ${c.senderContains.join(', ')}`);\n if (c.hasAttachments) parts.push('has attachments');\n if (c.importance) parts.push(`importance: ${c.importance}`);\n\n return parts.length > 0 ? parts.join('; ') : '(any)';\n}\n\n/** Short human string describing what the rule does. */\nexport function summariseActions(a?: RuleActions): string {\n if (!a) return '(none)';\n const parts: string[] = [];\n\n if (a.moveToFolder) parts.push(`move to [${a.moveToFolder}]`);\n if (a.copyToFolder) parts.push(`copy to [${a.copyToFolder}]`);\n if (a.delete) parts.push('delete');\n if (a.permanentDelete) parts.push('permanent delete');\n if (a.markAsRead) parts.push('mark read');\n if (a.markImportance) parts.push(`mark ${a.markImportance}`);\n\n const fwd = addrList(a.forwardTo);\n if (fwd) parts.push(`forward to: ${fwd}`);\n const redir = addrList(a.redirectTo);\n if (redir) parts.push(`redirect to: ${redir}`);\n\n if (a.stopProcessingRules) parts.push('stop processing');\n\n return parts.length > 0 ? parts.join('; ') : '(none)';\n}\n\nexport function renderRules(rules: MessageRule[]): string {\n if (rules.length === 0) return '(no rules)';\n\n const header = [\n '#'.padEnd(3),\n 'ENABLED'.padEnd(8),\n 'NAME'.padEnd(28),\n 'CONDITIONS'.padEnd(36),\n 'ACTIONS',\n ].join(' ');\n\n const rows = rules.map((r) => [\n String(r.sequence ?? '-').padEnd(3),\n (r.isEnabled ? 'yes' : 'no').padEnd(8),\n (r.displayName ?? '(unnamed)').slice(0, 28).padEnd(28),\n summariseConditions(r.conditions).slice(0, 36).padEnd(36),\n summariseActions(r.actions),\n ].join(' '));\n\n return [header, ...rows].join('\\n');\n}\n\n/* ---------- Create handler ---------- */\n\n/**\n * Build the Graph messageRule request body from CLI flags.\n *\n * Conditions:\n * --from <addr> → conditions.fromAddresses (repeatable)\n * --sender-contains <s> → conditions.senderContains (repeatable, for domain matching)\n *\n * Actions:\n * --folder <id> → actions.moveToFolder (required; opaque folder id)\n * --mark-read → actions.markAsRead = true\n * --stop-processing → actions.stopProcessingRules = true (default: true)\n *\n * Meta:\n * --name <text> → displayName (required)\n * --enabled → isEnabled (default: true)\n * --sequence <n> → sequence (optional; Graph auto-assigns if omitted)\n */\nfunction buildRuleBody(ctx: CommandContext): Record<string, unknown> {\n const name = ctx.args.require('name');\n const folderId = ctx.args.require('folder');\n\n // Conditions — at least one of --from or --sender-contains is required\n const fromAddrs = ctx.args.strAll('from');\n const senderContains = ctx.args.strAll('sender-contains');\n\n if (fromAddrs.length === 0 && senderContains.length === 0) {\n throw new UsageError(\n 'At least one condition is required: --from <address> and/or --sender-contains <domain>. ' +\n 'A rule with no condition would match every message.',\n );\n }\n\n const conditions: RuleConditions = {};\n if (fromAddrs.length > 0) {\n conditions.fromAddresses = fromAddrs.map((addr) => ({\n emailAddress: { address: addr },\n }));\n }\n if (senderContains.length > 0) {\n conditions.senderContains = senderContains;\n }\n\n // Actions\n const actions: RuleActions = {\n moveToFolder: folderId,\n };\n if (ctx.args.bool('mark-read')) {\n actions.markAsRead = true;\n }\n // Default to stopProcessingRules: true unless --no-stop-processing\n if (!ctx.args.has('stop-processing') || ctx.args.bool('stop-processing')) {\n actions.stopProcessingRules = true;\n }\n\n // Meta\n const body: Record<string, unknown> = {\n displayName: name,\n conditions,\n actions,\n isEnabled: !ctx.args.has('enabled') || ctx.args.bool('enabled'),\n };\n\n const seq = ctx.args.num('sequence');\n if (seq !== undefined) body.sequence = seq;\n\n return body;\n}\n\nasync function createHandler(ctx: CommandContext): Promise<void> {\n const body = buildRuleBody(ctx);\n const spec = ctx.client.buildSpec('POST', RULES_PATH, body);\n\n const created = await guardMutation(ctx, spec, async () =>\n ctx.client.post<MessageRule>(RULES_PATH, body),\n );\n\n if (created === undefined) return; // --dry-run already reported\n\n emit(ctx, created, () => {\n const name = created.displayName ?? '(unnamed)';\n const seq = created.sequence ?? '?';\n const cond = summariseConditions(created.conditions);\n const acts = summariseActions(created.actions);\n return `Created rule #${seq} \"${name}\"\\n Conditions: ${cond}\\n Actions: ${acts}`;\n });\n}\n\n/* ---------- Command handler ---------- */\n\nconst RULES_PATH = '/me/mailFolders/inbox/messageRules';\n\nasync function rulesHandler(ctx: CommandContext): Promise<void> {\n const sub = ctx.args.positionals[0] ?? 'list';\n\n switch (sub) {\n case 'list': {\n const response = await ctx.client.get<GraphCollection<MessageRule>>(RULES_PATH);\n const rules = response.value;\n emit(ctx, rules, () => renderRules(rules));\n return;\n }\n case 'create':\n return createHandler(ctx);\n default: {\n throw new UsageError(\n `Unknown rules subcommand \"${sub}\". Expected \"list\" or \"create\".`,\n );\n }\n }\n}\n\nexport const rulesCommand: CommandSpec = {\n name: 'rules',\n summary: 'List or create inbox message rules',\n usage:\n 'outlook rules [list] [--json]\\n' +\n ' outlook rules create --name <text> --folder <id>\\n' +\n ' [--from <addr>...] [--sender-contains <domain>...]\\n' +\n ' [--mark-read] [--stop-processing] [--enabled]\\n' +\n ' (--stop-processing defaults to on; use --no-stop-processing to disable)\\n' +\n ' [--dry-run] [--json]',\n mutating: true,\n handler: rulesHandler,\n};\n","/**\n * `outlook search <query>` — KQL/OData `$search` over messages\n * (docs/01-read-endpoints.md §4 \"`$search` and KQL (message search)\").\n *\n * Endpoint: `GET /me/messages?$search=...` by default, or\n * `GET /me/mailFolders/{id}/messages?$search=...` when `--folder` scopes the\n * search to one folder — docs/01 §3's intro line lists\n * `/me/mailFolders/{id}/messages` as one of the three endpoints that\n * \"supports the OData Query Parameters\" (of which `$search` is one),\n * alongside `/me/messages` and `/me/messages/{id}`.\n *\n * Quoting (docs/01 §4a, verbatim): \"the search string itself must be wrapped\n * in double quotes inside the query value (`$search=\"pizza\"`), per S12's own\n * examples.\" §4's general syntax rules add: \"embedded double quotes or\n * backslashes must be backslash-escaped; other special characters must be\n * URL-encoded.\" This command wraps the ENTIRE positional query in one outer\n * pair of double quotes and backslash-escapes any embedded `\"`/`\\` before\n * handing it to `collectItems`/`client.buildSpec` as the `$search` value;\n * percent-encoding of the resulting string (quotes included) is left to\n * buildSpec, exactly as for every other query parameter.\n *\n * Deliberately absent: `$orderby` and `$filter`. docs/01 §3.7/§9 document\n * `$search` on messages as carrying its own **built-in sort** — \"search\n * results for messages ... are sorted by the date and time the message was\n * sent\" (S12) — and flag `$search`+`$orderby` on `/me/messages` as an\n * unverified interaction: \"the CLI should defensively avoid the combination\n * ... and fall back to client-side sort if needed\" (§9 item 1). §3.7 flags\n * `$search`+`$filter` the same way for messages (§9 item 2: \"supported or\n * rejected\" unconfirmed). Unlike `list.ts` (which always sets\n * `$orderby=receivedDateTime desc`), this command never sends `$orderby` or\n * `$filter` at all — no flag here maps to either — so the documented risk\n * has no code path that could trigger it.\n *\n * `--limit` (default 25) is validated against the range docs/01 documents\n * for `$search` on messages specifically: \"up to 1,000 results\" (§4a) — the\n * same 1-1000 ceiling §3.5 gives generally for `$top`. A `--limit` outside\n * that range can never be honored by the API, so it is rejected locally as\n * a `UsageError` (naming the ceiling) instead of being sent as a request\n * guaranteed to misbehave.\n *\n * `--folder` scoping mirrors `folders.ts`'s tested behavior: a recognized\n * well-known name (`isWellKnownFolder`) is lowercased (well-known names are\n * documented case-insensitive, docs/01 §2); anything else is treated as a\n * raw folder id and percent-encoded.\n *\n * Read-only: `mutating: false`, no `guardMutation` (see get.ts — that\n * chokepoint is reserved for state-changing commands).\n */\n\nimport { emit, type CommandContext, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport { renderMessageList } from '../output.js';\nimport { collectItems } from '../paginate.js';\nimport { isWellKnownFolder, type Message } from '../types.js';\n\nconst MAX_RESULTS = 1000;\nconst SELECT = 'subject,from,receivedDateTime,isRead,hasAttachments,bodyPreview';\n\nfunction folderSegment(folder: string): string {\n return isWellKnownFolder(folder) ? folder.toLowerCase() : encodeURIComponent(folder);\n}\n\nfunction searchPath(folder: string | undefined): string {\n if (folder === undefined) return '/me/messages';\n return `/me/mailFolders/${folderSegment(folder)}/messages`;\n}\n\n/**\n * Wraps the whole query in one outer pair of double quotes and\n * backslash-escapes embedded `\"`/`\\`, per docs/01 §4's quoting rules.\n * Backslashes are escaped first so the quote-escaping step doesn't\n * re-escape the backslashes it just inserted.\n */\nfunction quoteSearch(query: string): string {\n const escaped = query.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n return `\"${escaped}\"`;\n}\n\nfunction readLimit(ctx: CommandContext): number {\n if (!ctx.args.has('limit')) return 25;\n const limit = ctx.args.num('limit');\n if (limit === undefined || !Number.isInteger(limit) || limit < 1 || limit > MAX_RESULTS) {\n throw new UsageError(\n `--limit must be an integer between 1 and ${MAX_RESULTS} — docs/01 §4a ` +\n `documents $search on messages as returning \"up to 1,000 results\"`,\n );\n }\n return limit;\n}\n\nasync function searchHandler(ctx: CommandContext): Promise<void> {\n const query = ctx.args.requirePositional(0, '<query>');\n const limit = readLimit(ctx);\n const all = ctx.args.bool('all');\n const folder = ctx.args.str('folder');\n\n const messages = await collectItems<Message>(ctx.client, searchPath(folder), {\n query: { $search: quoteSearch(query), $select: SELECT, $top: limit },\n limit,\n all,\n });\n\n emit(ctx, messages, () => renderMessageList(messages));\n}\n\nexport const searchCommand: CommandSpec = {\n name: 'search',\n summary: 'Search messages with KQL/$search',\n usage: 'outlook search <query> [--limit <n>] [--all] [--folder <name|id>] [--json]',\n mutating: false,\n handler: searchHandler,\n};\n","/**\n * `outlook send` — POST /me/sendMail.\n *\n * This is the most irreversible command in the CLI: it delivers real mail to\n * real people and cannot be recalled. Two invariants:\n * 1. The Graph call is wrapped in `guardMutation`, so --dry-run short-circuits\n * before any network I/O.\n * 2. No retry. client.ts refuses to retry POST because sendMail carries no\n * idempotency guarantee (docs/02 §8) — a retry double-sends.\n *\n * sendMail returns 202 Accepted with NO body, so there is no Message to parse.\n */\n\nimport { emit, guardMutation, type CommandSpec } from '../command.js';\nimport { UsageError } from '../errors.js';\nimport { resolveSignature } from '../signature.js';\nimport {\n composeMessage,\n describeRecipients,\n saveToSentItems,\n signMessage,\n} from './compose.js';\n\nexport const sendCommand: CommandSpec = {\n name: 'send',\n summary: 'Send an email',\n usage:\n 'outlook send --to <addr> [--to <addr>...] --subject <text> ' +\n '[--cc <addr>] [--bcc <addr>] [--body <text> | --body-file <path>] ' +\n '[--html] [--attach <path>...] [--signature <path> | --no-signature] ' +\n '[--no-save-sent] [--dry-run] [--json]',\n mutating: true,\n\n async handler(ctx) {\n // Compose first, validate --to/--subject, then resolve + apply\n // signature — so a missing recipient surfaces before a bad signature path.\n const message = await composeMessage(ctx.args);\n\n if (!message.toRecipients || message.toRecipients.length === 0) {\n throw new UsageError(\n 'At least one recipient is required. Use --to <address> ' +\n '(repeatable, or comma-separated).',\n );\n }\n if (message.subject === undefined || message.subject.trim() === '') {\n throw new UsageError('--subject is required.');\n }\n\n const signature = await resolveSignature(ctx.args, ctx.env);\n signMessage(message, signature, ctx.args);\n\n const payload = {\n message,\n saveToSentItems: saveToSentItems(ctx.args),\n };\n\n const spec = ctx.client.buildSpec('POST', '/me/sendMail', payload);\n\n const sent = await guardMutation(ctx, spec, async () => {\n await ctx.client.post<void>('/me/sendMail', payload);\n return true;\n });\n\n if (sent === undefined) return; // --dry-run already reported\n\n const to = describeRecipients(message.toRecipients);\n emit(\n ctx,\n {\n sent: true,\n subject: message.subject,\n to: message.toRecipients.map((r) => r.emailAddress.address),\n attachments: message.attachments?.length ?? 0,\n savedToSentItems: payload.saveToSentItems,\n signatureApplied: signature !== undefined,\n },\n () => `Sent \"${message.subject}\" to ${to}`,\n );\n },\n};\n"],"mappings":"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","names":["homedir","join","join","homedir","resolve","defaultSleep","isTokenResponse","resolve","defaultSleep","isAbsolute","trimmed","resolve","join","join","mkdir","writeFile","basename","dirname","join","resolve","dirname","readFile","readFile","dirname","readFile","stat","stat","readFile","basename","resolve","dirname","stem","join","writeFile","mkdir","SUBCOMMANDS","listHandler","readFile","trimmed","readFile","readFile","readFile","SUBCOMMANDS","listHandler","getHandler","MAX_TOP","readLimit","listHandler","messagePath","escapeHtml","createHandler","SELECT","readLimit","searchHandler"]}