inboxctl 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -0
- package/LICENSE +21 -0
- package/README.md +277 -0
- package/dist/chunk-EY6VV43S.js +4744 -0
- package/dist/chunk-EY6VV43S.js.map +1 -0
- package/dist/cli.js +4668 -0
- package/dist/cli.js.map +1 -0
- package/dist/mcp.js +16 -0
- package/dist/mcp.js.map +1 -0
- package/package.json +83 -0
- package/rules/example.yaml +29 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/server.ts","../src/core/actions/audit.ts","../src/config.ts","../src/core/db/client.ts","../src/core/db/schema.ts","../src/core/gmail/transport_google_api.ts","../src/core/auth/tokens.ts","../src/core/auth/oauth.ts","../src/core/gmail/client.ts","../src/core/gmail/transport_rest.ts","../src/core/gmail/transport.ts","../src/core/gmail/messages.ts","../src/core/gmail/labels.ts","../src/core/gmail/modify.ts","../src/core/actions/undo.ts","../src/core/gmail/threads.ts","../src/core/stats/common.ts","../src/core/stats/labels.ts","../src/core/stats/newsletters.ts","../src/core/stats/sender.ts","../src/core/stats/volume.ts","../src/core/rules/history.ts","../src/core/rules/deploy.ts","../src/core/rules/loader.ts","../src/core/rules/types.ts","../src/core/rules/matcher.ts","../src/core/rules/executor.ts","../src/core/gmail/filters.ts","../src/core/sync/cache.ts","../src/core/sync/sync.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { getRecentRuns } from \"../core/actions/audit.js\";\nimport { undoRun } from \"../core/actions/undo.js\";\nimport { loadConfig, getGoogleCredentialStatus } from \"../config.js\";\nimport { loadTokens } from \"../core/auth/tokens.js\";\nimport { initializeDb } from \"../core/db/client.js\";\nimport { getGmailReadiness } from \"../core/gmail/client.js\";\nimport { createLabel, listLabels } from \"../core/gmail/labels.js\";\nimport { getMessage, listMessages } from \"../core/gmail/messages.js\";\nimport {\n archiveEmails,\n forwardEmail,\n labelEmails,\n markRead,\n markUnread,\n unlabelEmails,\n} from \"../core/gmail/modify.js\";\nimport { getThread } from \"../core/gmail/threads.js\";\nimport { getLabelDistribution } from \"../core/stats/labels.js\";\nimport { getNewsletters } from \"../core/stats/newsletters.js\";\nimport { getSenderStats, getTopSenders } from \"../core/stats/sender.js\";\nimport { getInboxOverview, getVolumeByPeriod } from \"../core/stats/volume.js\";\nimport { getExecutionHistory } from \"../core/rules/history.js\";\nimport {\n deployRule,\n disableRule,\n enableRule,\n getAllRulesStatus,\n} from \"../core/rules/deploy.js\";\nimport { parseRuleYaml, hashRule } from \"../core/rules/loader.js\";\nimport { runRule } from \"../core/rules/executor.js\";\nimport {\n createFilter,\n deleteFilter,\n getFilter,\n listFilters,\n} from \"../core/gmail/filters.js\";\nimport { getRecentEmails } from \"../core/sync/cache.js\";\nimport { fullSync, getSyncStatus, incrementalSync } from \"../core/sync/sync.js\";\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst MCP_VERSION = \"0.1.0\";\n\nexport const MCP_TOOLS = [\n \"search_emails\",\n \"get_email\",\n \"get_thread\",\n \"sync_inbox\",\n \"archive_emails\",\n \"label_emails\",\n \"mark_read\",\n \"forward_email\",\n \"undo_run\",\n \"get_labels\",\n \"create_label\",\n \"get_inbox_stats\",\n \"get_top_senders\",\n \"get_sender_stats\",\n \"get_newsletter_senders\",\n \"deploy_rule\",\n \"list_rules\",\n \"run_rule\",\n \"enable_rule\",\n \"disable_rule\",\n \"list_filters\",\n \"get_filter\",\n \"create_filter\",\n \"delete_filter\",\n] as const;\n\nexport const MCP_RESOURCES = [\n \"inbox://recent\",\n \"inbox://summary\",\n \"rules://deployed\",\n \"rules://history\",\n \"stats://senders\",\n \"stats://overview\",\n] as const;\n\nexport const MCP_PROMPTS = [\n \"summarize-inbox\",\n \"review-senders\",\n \"find-newsletters\",\n \"suggest-rules\",\n \"triage-inbox\",\n] as const;\n\nexport interface McpServerContract {\n transport: \"stdio\";\n tools: readonly string[];\n resources: readonly string[];\n prompts: readonly string[];\n ready: true;\n warnings: string[];\n}\n\nfunction toTextResult(value: unknown) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(value, null, 2),\n },\n ],\n structuredContent: {\n result: value,\n },\n };\n}\n\nfunction toErrorResult(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: message,\n },\n ],\n structuredContent: {\n error: {\n message,\n },\n },\n isError: true,\n };\n}\n\nfunction toolHandler<TArgs extends Record<string, unknown> | undefined>(\n handler: (args: TArgs) => Promise<unknown>,\n) {\n return async (args: TArgs) => {\n try {\n return toTextResult(await handler(args));\n } catch (error) {\n return toErrorResult(error);\n }\n };\n}\n\nfunction resourceText(uri: string, value: unknown) {\n return {\n contents: [\n {\n uri,\n mimeType: \"application/json\",\n text: JSON.stringify(value, null, 2),\n },\n ],\n };\n}\n\nfunction promptResult(description: string, text: string) {\n return {\n description,\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text,\n },\n },\n ],\n };\n}\n\nfunction buildSearchQuery(query: string, label?: string): string {\n const trimmedQuery = query.trim();\n const trimmedLabel = label?.trim();\n\n if (trimmedLabel) {\n return trimmedQuery ? `${trimmedQuery} label:${trimmedLabel}` : `label:${trimmedLabel}`;\n }\n\n return trimmedQuery;\n}\n\nfunction uniqueStrings(values: string[] | undefined): string[] {\n return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));\n}\n\nfunction resolveResourceUri(uri: unknown, fallback: string): string {\n return typeof uri === \"string\" ? uri : fallback;\n}\n\nasync function buildStartupWarnings(): Promise<string[]> {\n const config = loadConfig();\n initializeDb(config.dbPath);\n\n const warnings: string[] = [];\n const tokens = await loadTokens(config.tokensPath);\n const readiness = getGmailReadiness(config, tokens);\n const googleStatus = getGoogleCredentialStatus(config);\n const syncStatus = await getSyncStatus();\n const latestSync = Math.max(syncStatus.lastIncrementalSync ?? 0, syncStatus.lastFullSync ?? 0);\n\n if (!readiness.ready) {\n const missing = [\n ...googleStatus.missing,\n ...(tokens ? [] : [\"gmail_tokens\"]),\n ];\n warnings.push(\n `Gmail auth is incomplete (${missing.join(\", \")}). Live Gmail MCP tools will fail until \\`inboxctl auth login\\` is complete.`,\n );\n }\n\n if (!latestSync) {\n warnings.push(\"Inbox cache has not been synced yet. Stats and resources will be empty until `sync_inbox` runs.\");\n } else if (Date.now() - latestSync > DAY_MS) {\n warnings.push(\"Inbox cache appears stale (last sync older than 24 hours). Call `sync_inbox` if freshness matters.\");\n }\n\n return warnings;\n}\n\nasync function buildStatsOverview() {\n return {\n overview: await getInboxOverview(),\n topSenders: await getTopSenders({ limit: 10 }),\n labelDistribution: (await getLabelDistribution()).slice(0, 10),\n dailyVolume: await getVolumeByPeriod(\"day\", {\n start: Date.now() - 30 * DAY_MS,\n end: Date.now(),\n }),\n };\n}\n\nasync function buildRuleHistory() {\n const runs = await getExecutionHistory(undefined, 20);\n return {\n runs,\n recentRuns: await getRecentRuns(20),\n };\n}\n\nexport async function createMcpServer(): Promise<{\n contract: McpServerContract;\n server: McpServer;\n}> {\n const warnings = await buildStartupWarnings();\n const server = new McpServer({\n name: \"inboxctl\",\n version: MCP_VERSION,\n });\n\n server.registerTool(\n \"search_emails\",\n {\n description: \"Search Gmail using Gmail query syntax and return matching email metadata.\",\n inputSchema: {\n query: z.string().min(1),\n max_results: z.number().int().positive().max(100).optional(),\n label: z.string().min(1).optional(),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async ({ query, max_results, label }) => {\n return listMessages(buildSearchQuery(query, label), max_results ?? 20);\n }),\n );\n\n server.registerTool(\n \"get_email\",\n {\n description: \"Fetch a single email with full content by Gmail message ID.\",\n inputSchema: {\n email_id: z.string().min(1),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async ({ email_id }) => getMessage(email_id)),\n );\n\n server.registerTool(\n \"get_thread\",\n {\n description: \"Fetch a full Gmail thread by thread ID.\",\n inputSchema: {\n thread_id: z.string().min(1),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async ({ thread_id }) => getThread(thread_id)),\n );\n\n server.registerTool(\n \"sync_inbox\",\n {\n description: \"Run inbox sync. Uses incremental sync by default and full sync when requested.\",\n inputSchema: {\n full: z.boolean().optional(),\n },\n annotations: {\n readOnlyHint: false,\n idempotentHint: false,\n },\n },\n toolHandler(async ({ full }) => (full ? fullSync() : incrementalSync())),\n );\n\n server.registerTool(\n \"archive_emails\",\n {\n description: \"Archive one or more Gmail messages by removing the INBOX label.\",\n inputSchema: {\n email_ids: z.array(z.string().min(1)).min(1),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ email_ids }) => archiveEmails(uniqueStrings(email_ids))),\n );\n\n server.registerTool(\n \"label_emails\",\n {\n description: \"Add and/or remove Gmail labels on one or more messages.\",\n inputSchema: {\n email_ids: z.array(z.string().min(1)).min(1),\n add_labels: z.array(z.string().min(1)).optional(),\n remove_labels: z.array(z.string().min(1)).optional(),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ email_ids, add_labels, remove_labels }) => {\n const ids = uniqueStrings(email_ids);\n const addLabels = uniqueStrings(add_labels);\n const removeLabels = uniqueStrings(remove_labels);\n\n if (addLabels.length === 0 && removeLabels.length === 0) {\n throw new Error(\"Provide at least one label to add or remove.\");\n }\n\n const operations = [];\n\n for (const label of addLabels) {\n operations.push(await labelEmails(ids, label));\n }\n\n for (const label of removeLabels) {\n operations.push(await unlabelEmails(ids, label));\n }\n\n return {\n emailIds: ids,\n addLabels,\n removeLabels,\n operations,\n };\n }),\n );\n\n server.registerTool(\n \"mark_read\",\n {\n description: \"Mark one or more Gmail messages as read or unread.\",\n inputSchema: {\n email_ids: z.array(z.string().min(1)).min(1),\n read: z.boolean(),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ email_ids, read }) => {\n const ids = uniqueStrings(email_ids);\n return read ? markRead(ids) : markUnread(ids);\n }),\n );\n\n server.registerTool(\n \"forward_email\",\n {\n description: \"Forward a Gmail message to another address.\",\n inputSchema: {\n email_id: z.string().min(1),\n to: z.string().email(),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ email_id, to }) => forwardEmail(email_id, to)),\n );\n\n server.registerTool(\n \"undo_run\",\n {\n description: \"Undo a prior inboxctl action run when the underlying Gmail mutations are reversible.\",\n inputSchema: {\n run_id: z.string().min(1),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ run_id }) => undoRun(run_id)),\n );\n\n server.registerTool(\n \"get_labels\",\n {\n description: \"List Gmail labels with message and unread counts.\",\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async () => listLabels()),\n );\n\n server.registerTool(\n \"create_label\",\n {\n description: \"Create a Gmail label if it does not already exist.\",\n inputSchema: {\n name: z.string().min(1),\n color: z.string().min(1).optional(),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ name, color }) => {\n const label = await createLabel(name);\n return {\n label,\n requestedColor: color ?? null,\n colorApplied: false,\n note: color ? \"Color hints are not applied yet; the label was created with Gmail defaults.\" : null,\n };\n }),\n );\n\n server.registerTool(\n \"get_inbox_stats\",\n {\n description: \"Return inbox overview counts from the local SQLite cache.\",\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async () => getInboxOverview()),\n );\n\n server.registerTool(\n \"get_top_senders\",\n {\n description: \"Return top senders ranked by cached email volume.\",\n inputSchema: {\n limit: z.number().int().positive().max(100).optional(),\n min_unread_rate: z.number().min(0).max(100).optional(),\n period: z.enum([\"day\", \"week\", \"month\", \"year\", \"all\"]).optional(),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async ({ limit, min_unread_rate, period }) =>\n getTopSenders({\n limit,\n minUnreadRate: min_unread_rate,\n period,\n })),\n );\n\n server.registerTool(\n \"get_sender_stats\",\n {\n description: \"Return detailed stats for a sender email address or an @domain aggregate.\",\n inputSchema: {\n email_or_domain: z.string().min(1),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async ({ email_or_domain }) => {\n const result = await getSenderStats(email_or_domain);\n return {\n query: email_or_domain,\n found: result !== null,\n result,\n };\n }),\n );\n\n server.registerTool(\n \"get_newsletter_senders\",\n {\n description: \"Return senders that look like newsletters or mailing lists based on cached heuristics.\",\n inputSchema: {\n min_messages: z.number().int().positive().optional(),\n min_unread_rate: z.number().min(0).max(100).optional(),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async ({ min_messages, min_unread_rate }) =>\n getNewsletters({\n minMessages: min_messages,\n minUnreadRate: min_unread_rate,\n })),\n );\n\n server.registerTool(\n \"deploy_rule\",\n {\n description: \"Validate and deploy a rule directly from YAML content.\",\n inputSchema: {\n yaml_content: z.string().min(1),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ yaml_content }) => {\n const rule = parseRuleYaml(yaml_content, \"<mcp:deploy_rule>\");\n return deployRule(rule, hashRule(yaml_content));\n }),\n );\n\n server.registerTool(\n \"list_rules\",\n {\n description: \"List deployed inboxctl rules and their execution status.\",\n inputSchema: {\n enabled_only: z.boolean().optional(),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n toolHandler(async ({ enabled_only }) => {\n const rules = await getAllRulesStatus();\n return enabled_only ? rules.filter((rule) => rule.enabled) : rules;\n }),\n );\n\n server.registerTool(\n \"run_rule\",\n {\n description: \"Run a deployed rule in dry-run mode by default, or apply it when dry_run is false.\",\n inputSchema: {\n rule_name: z.string().min(1),\n dry_run: z.boolean().optional(),\n max_emails: z.number().int().positive().max(1000).optional(),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ rule_name, dry_run, max_emails }) =>\n runRule(rule_name, {\n dryRun: dry_run,\n maxEmails: max_emails,\n })),\n );\n\n server.registerTool(\n \"enable_rule\",\n {\n description: \"Enable a deployed rule by name.\",\n inputSchema: {\n rule_name: z.string().min(1),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ rule_name }) => enableRule(rule_name)),\n );\n\n server.registerTool(\n \"disable_rule\",\n {\n description: \"Disable a deployed rule by name.\",\n inputSchema: {\n rule_name: z.string().min(1),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n },\n },\n toolHandler(async ({ rule_name }) => disableRule(rule_name)),\n );\n\n server.registerResource(\n \"recent-inbox\",\n \"inbox://recent\",\n {\n description: \"Recent cached inbox email metadata.\",\n mimeType: \"application/json\",\n },\n async (uri) => resourceText(resolveResourceUri(uri, \"inbox://recent\"), await getRecentEmails(50)),\n );\n\n server.registerResource(\n \"inbox-summary\",\n \"inbox://summary\",\n {\n description: \"Inbox overview counts from the local cache.\",\n mimeType: \"application/json\",\n },\n async (uri) => resourceText(resolveResourceUri(uri, \"inbox://summary\"), await getInboxOverview()),\n );\n\n server.registerResource(\n \"deployed-rules\",\n \"rules://deployed\",\n {\n description: \"All deployed rules with status and run counts.\",\n mimeType: \"application/json\",\n },\n async (uri) => resourceText(resolveResourceUri(uri, \"rules://deployed\"), await getAllRulesStatus()),\n );\n\n server.registerResource(\n \"rules-history\",\n \"rules://history\",\n {\n description: \"Recent execution run history across manual actions and rules.\",\n mimeType: \"application/json\",\n },\n async (uri) => resourceText(resolveResourceUri(uri, \"rules://history\"), await buildRuleHistory()),\n );\n\n server.registerResource(\n \"stats-senders\",\n \"stats://senders\",\n {\n description: \"Top cached senders ranked by message volume.\",\n mimeType: \"application/json\",\n },\n async (uri) => resourceText(resolveResourceUri(uri, \"stats://senders\"), await getTopSenders({ limit: 20 })),\n );\n\n server.registerResource(\n \"stats-overview\",\n \"stats://overview\",\n {\n description: \"Combined inbox overview, sender, label, and volume stats from the local cache.\",\n mimeType: \"application/json\",\n },\n async (uri) => resourceText(resolveResourceUri(uri, \"stats://overview\"), await buildStatsOverview()),\n );\n\n server.registerPrompt(\n \"summarize-inbox\",\n {\n description: \"Review inbox summary and recent mail, then suggest a short action plan.\",\n },\n async () =>\n promptResult(\n \"Summarize the inbox using inboxctl resources and tools.\",\n [\n \"Use `inbox://summary` and `inbox://recent` first.\",\n \"Summarize the current inbox state, call out anything urgent, and note sender or unread patterns.\",\n \"If the cache looks stale, suggest calling `sync_inbox` before drawing conclusions.\",\n \"Finish with 2-3 concrete actions the user could take now.\",\n ].join(\"\\n\"),\n ),\n );\n\n server.registerPrompt(\n \"review-senders\",\n {\n description: \"Review top senders and identify likely noise or cleanup opportunities.\",\n },\n async () =>\n promptResult(\n \"Review top senders and recommend cleanup actions.\",\n [\n \"Use `get_top_senders` and `stats://senders`.\",\n \"Focus on senders with high unread rates or high volume.\",\n \"For each notable sender, classify them as important, FYI, newsletter, or noise.\",\n \"Recommend one of: keep, unsubscribe, archive manually, or create a rule.\",\n ].join(\"\\n\"),\n ),\n );\n\n server.registerPrompt(\n \"find-newsletters\",\n {\n description: \"Find likely newsletters and low-value bulk senders.\",\n },\n async () =>\n promptResult(\n \"Find newsletter-like senders and suggest which ones to keep versus clean up.\",\n [\n \"Use `get_newsletter_senders` and `get_top_senders` with a high unread threshold.\",\n \"Highlight senders with unsubscribe links, high unread rates, or obvious newsletter patterns.\",\n \"Separate likely keepers from likely unsubscribe/archive candidates.\",\n \"Suggest follow-up actions such as `archive_emails`, `label_emails`, or a new rule.\",\n ].join(\"\\n\"),\n ),\n );\n\n server.registerPrompt(\n \"suggest-rules\",\n {\n description: \"Suggest inboxctl YAML automation rules from observed inbox patterns.\",\n },\n async () =>\n promptResult(\n \"Analyze inbox patterns and propose valid inboxctl rule YAML.\",\n [\n \"Inspect `rules://deployed`, `stats://senders`, and `get_newsletter_senders` first.\",\n \"Look for ignored senders, repetitive notifications, and obvious auto-label opportunities.\",\n \"For each recommendation, explain why it is safe and include complete YAML the user could deploy with `deploy_rule`.\",\n \"Avoid risky suggestions when the evidence is weak.\",\n ].join(\"\\n\"),\n ),\n );\n\n server.registerPrompt(\n \"triage-inbox\",\n {\n description: \"Help categorize unread mail into action required, FYI, and noise.\",\n },\n async () =>\n promptResult(\n \"Triage unread mail using inboxctl data sources.\",\n [\n \"Use `inbox://recent`, `inbox://summary`, and `search_emails` for `is:unread` if needed.\",\n \"Group unread mail into ACTION REQUIRED, FYI, and NOISE.\",\n \"For NOISE, suggest batch actions or rules that would reduce future inbox load.\",\n \"Call out any assumptions when message bodies are unavailable.\",\n ].join(\"\\n\"),\n ),\n );\n\n server.registerTool(\n \"list_filters\",\n {\n description:\n \"List all Gmail server-side filters. These run automatically on incoming mail at delivery time — no client needed. For complex matching (regex, AND/OR, snippet), historical mail, or auditable/undoable operations, use YAML rules (list_rules) instead.\",\n },\n toolHandler(async () => listFilters()),\n );\n\n server.registerTool(\n \"get_filter\",\n {\n description: \"Get the details of a specific Gmail server-side filter by ID.\",\n inputSchema: {\n filter_id: z.string().min(1).describe(\"Gmail filter ID\"),\n },\n },\n toolHandler(async ({ filter_id }) => getFilter(filter_id)),\n );\n\n server.registerTool(\n \"create_filter\",\n {\n description:\n \"Create a Gmail server-side filter that applies automatically to all future incoming mail. Useful for simple, always-on rules (e.g. 'label all mail from newsletter@x.com and archive it'). At least one criteria field and one action field are required. Gmail does not support updating filters — to change one, delete it and create a new one. For regex matching, OR conditions, snippet matching, or processing existing mail, use YAML rules instead.\",\n inputSchema: {\n from: z.string().optional().describe(\"Match emails from this address\"),\n to: z.string().optional().describe(\"Match emails sent to this address\"),\n subject: z.string().optional().describe(\"Match emails with this text in the subject\"),\n query: z.string().optional().describe(\"Match using Gmail search syntax (e.g. 'has:attachment')\"),\n negated_query: z.string().optional().describe(\"Exclude emails matching this Gmail query\"),\n has_attachment: z.boolean().optional().describe(\"Match emails with attachments\"),\n exclude_chats: z.boolean().optional().describe(\"Exclude chat messages from matches\"),\n size: z.number().int().positive().optional().describe(\"Size threshold in bytes\"),\n size_comparison: z.enum([\"larger\", \"smaller\"]).optional().describe(\"Use with size: match emails larger or smaller than the threshold\"),\n label: z.string().optional().describe(\"Apply this label to matching emails (auto-created if it does not exist)\"),\n archive: z.boolean().optional().describe(\"Archive matching emails (remove from inbox)\"),\n mark_read: z.boolean().optional().describe(\"Mark matching emails as read\"),\n star: z.boolean().optional().describe(\"Star matching emails\"),\n forward: z.string().email().optional().describe(\"Forward matching emails to this address (address must be verified in Gmail settings)\"),\n },\n },\n toolHandler(async (args) =>\n createFilter({\n from: args.from,\n to: args.to,\n subject: args.subject,\n query: args.query,\n negatedQuery: args.negated_query,\n hasAttachment: args.has_attachment,\n excludeChats: args.exclude_chats,\n size: args.size,\n sizeComparison: args.size_comparison,\n labelName: args.label,\n archive: args.archive,\n markRead: args.mark_read,\n star: args.star,\n forward: args.forward,\n }),\n ),\n );\n\n server.registerTool(\n \"delete_filter\",\n {\n description:\n \"Delete a Gmail server-side filter by ID. The filter stops processing future mail immediately. Already-processed mail is not affected. Use list_filters to find filter IDs.\",\n inputSchema: {\n filter_id: z.string().min(1).describe(\"Gmail filter ID to delete\"),\n },\n },\n toolHandler(async ({ filter_id }) => {\n await deleteFilter(filter_id);\n return { deleted: true, filter_id };\n }),\n );\n\n return {\n contract: {\n transport: \"stdio\",\n tools: MCP_TOOLS,\n resources: MCP_RESOURCES,\n prompts: MCP_PROMPTS,\n ready: true,\n warnings,\n },\n server,\n };\n}\n\nexport async function startMcpServer(): Promise<McpServerContract> {\n const { contract, server } = await createMcpServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n for (const warning of contract.warnings) {\n console.error(`[inboxctl:mcp] ${warning}`);\n }\n\n return contract;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport type { Action as RuleAction } from \"../rules/types.js\";\n\nexport type ExecutionSourceType = \"manual\" | \"rule\";\nexport type ExecutionRunStatus = \"planned\" | \"applied\" | \"partial\" | \"error\" | \"undone\";\nexport type ExecutionItemStatus = \"planned\" | \"applied\" | \"warning\" | \"error\" | \"undone\";\n\nexport type AuditAction = RuleAction;\n\nexport interface CreateExecutionRunInput {\n id?: string;\n sourceType: ExecutionSourceType;\n ruleId?: string | null;\n dryRun?: boolean;\n requestedActions?: AuditAction[];\n query?: string | null;\n status?: ExecutionRunStatus;\n createdAt?: number;\n undoneAt?: number | null;\n}\n\nexport interface AppendExecutionItemInput {\n id?: string;\n emailId: string;\n status: ExecutionItemStatus;\n appliedActions?: AuditAction[];\n beforeLabelIds: string[];\n afterLabelIds: string[];\n errorMessage?: string | null;\n executedAt?: number;\n undoneAt?: number | null;\n}\n\nexport interface ExecutionRunRecord {\n id: string;\n sourceType: ExecutionSourceType;\n ruleId: string | null;\n dryRun: boolean;\n requestedActions: AuditAction[];\n query: string | null;\n status: ExecutionRunStatus;\n createdAt: number;\n undoneAt: number | null;\n itemCount: number;\n plannedItemCount: number;\n appliedItemCount: number;\n warningItemCount: number;\n errorItemCount: number;\n undoneItemCount: number;\n}\n\nexport interface ExecutionItemRecord {\n id: string;\n runId: string;\n emailId: string;\n status: ExecutionItemStatus;\n appliedActions: AuditAction[];\n beforeLabelIds: string[];\n afterLabelIds: string[];\n errorMessage: string | null;\n executedAt: number;\n undoneAt: number | null;\n}\n\nfunction getDatabase() {\n const config = loadConfig();\n return getSqlite(config.dbPath);\n}\n\nfunction ensureValidSourceType(sourceType: string): asserts sourceType is ExecutionSourceType {\n if (sourceType !== \"manual\" && sourceType !== \"rule\") {\n throw new Error(`Invalid execution source type: ${sourceType}`);\n }\n}\n\nfunction ensureValidRunStatus(status: string): asserts status is ExecutionRunStatus {\n if (status !== \"planned\" && status !== \"applied\" && status !== \"partial\" && status !== \"error\" && status !== \"undone\") {\n throw new Error(`Invalid execution run status: ${status}`);\n }\n}\n\nfunction ensureValidItemStatus(status: string): asserts status is ExecutionItemStatus {\n if (status !== \"planned\" && status !== \"applied\" && status !== \"warning\" && status !== \"error\" && status !== \"undone\") {\n throw new Error(`Invalid execution item status: ${status}`);\n }\n}\n\nfunction parseJsonArray<T>(raw: string | null | undefined, fallback: T[]): T[] {\n if (!raw) {\n return fallback;\n }\n\n try {\n const parsed = JSON.parse(raw) as unknown;\n return Array.isArray(parsed) ? (parsed as T[]) : fallback;\n } catch {\n return fallback;\n }\n}\n\nfunction parseJsonObjectArray(raw: string | null | undefined): AuditAction[] {\n return parseJsonArray<AuditAction>(raw, []);\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value ?? []);\n}\n\nfunction rowToExecutionRun(row: {\n id: string;\n sourceType: string;\n ruleId: string | null;\n dryRun: number | null;\n requestedActions: string;\n query: string | null;\n status: string;\n createdAt: number | null;\n undoneAt: number | null;\n itemCount: number;\n plannedItemCount: number;\n appliedItemCount: number;\n warningItemCount: number;\n errorItemCount: number;\n undoneItemCount: number;\n}): ExecutionRunRecord {\n ensureValidSourceType(row.sourceType);\n ensureValidRunStatus(row.status);\n\n return {\n id: row.id,\n sourceType: row.sourceType,\n ruleId: row.ruleId,\n dryRun: row.dryRun === 1,\n requestedActions: parseJsonObjectArray(row.requestedActions),\n query: row.query,\n status: row.status,\n createdAt: row.createdAt ?? 0,\n undoneAt: row.undoneAt ?? null,\n itemCount: row.itemCount,\n plannedItemCount: row.plannedItemCount,\n appliedItemCount: row.appliedItemCount,\n warningItemCount: row.warningItemCount,\n errorItemCount: row.errorItemCount,\n undoneItemCount: row.undoneItemCount,\n };\n}\n\nfunction rowToExecutionItem(row: {\n id: string;\n runId: string;\n emailId: string;\n status: string;\n appliedActions: string;\n beforeLabelIds: string;\n afterLabelIds: string;\n errorMessage: string | null;\n executedAt: number | null;\n undoneAt: number | null;\n}): ExecutionItemRecord {\n ensureValidItemStatus(row.status);\n\n return {\n id: row.id,\n runId: row.runId,\n emailId: row.emailId,\n status: row.status,\n appliedActions: parseJsonObjectArray(row.appliedActions),\n beforeLabelIds: parseJsonArray<string>(row.beforeLabelIds, []),\n afterLabelIds: parseJsonArray<string>(row.afterLabelIds, []),\n errorMessage: row.errorMessage,\n executedAt: row.executedAt ?? 0,\n undoneAt: row.undoneAt ?? null,\n };\n}\n\nfunction queryRuns(\n whereClause: string = \"\",\n params: unknown[] = [],\n limit?: number,\n): ExecutionRunRecord[] {\n const sqlite = getDatabase();\n const sql = `\n SELECT\n r.id AS id,\n r.source_type AS sourceType,\n r.rule_id AS ruleId,\n r.dry_run AS dryRun,\n r.requested_actions AS requestedActions,\n r.query AS query,\n r.status AS status,\n r.created_at AS createdAt,\n r.undone_at AS undoneAt,\n COUNT(i.id) AS itemCount,\n COALESCE(SUM(CASE WHEN i.status = 'planned' THEN 1 ELSE 0 END), 0) AS plannedItemCount,\n COALESCE(SUM(CASE WHEN i.status = 'applied' THEN 1 ELSE 0 END), 0) AS appliedItemCount,\n COALESCE(SUM(CASE WHEN i.status = 'warning' THEN 1 ELSE 0 END), 0) AS warningItemCount,\n COALESCE(SUM(CASE WHEN i.status = 'error' THEN 1 ELSE 0 END), 0) AS errorItemCount,\n COALESCE(SUM(CASE WHEN i.status = 'undone' THEN 1 ELSE 0 END), 0) AS undoneItemCount\n FROM execution_runs r\n LEFT JOIN execution_items i ON i.run_id = r.id\n ${whereClause}\n GROUP BY r.id\n ORDER BY COALESCE(r.created_at, 0) DESC, r.id DESC\n ${limit ? \"LIMIT ?\" : \"\"}\n `;\n\n const rows = limit === undefined\n ? sqlite.prepare(sql).all(...params)\n : sqlite.prepare(sql).all(...params, limit);\n\n return (rows as Parameters<typeof rowToExecutionRun>[0][]).map(rowToExecutionRun);\n}\n\nexport async function createExecutionRun(\n input: CreateExecutionRunInput,\n): Promise<ExecutionRunRecord> {\n ensureValidSourceType(input.sourceType);\n const sqlite = getDatabase();\n const now = input.createdAt ?? Date.now();\n const id = input.id ?? randomUUID();\n const status = input.status ?? \"planned\";\n ensureValidRunStatus(status);\n\n sqlite\n .prepare(\n `\n INSERT INTO execution_runs (\n id, source_type, rule_id, dry_run, requested_actions, query, status, created_at, undone_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `,\n )\n .run(\n id,\n input.sourceType,\n input.ruleId ?? null,\n input.dryRun ? 1 : 0,\n serializeJson(input.requestedActions ?? []),\n input.query ?? null,\n status,\n now,\n input.undoneAt ?? null,\n );\n\n return (await getRun(id)) as ExecutionRunRecord;\n}\n\nexport async function appendExecutionItem(\n runId: string,\n input: AppendExecutionItemInput,\n): Promise<ExecutionItemRecord> {\n const sqlite = getDatabase();\n const runExists = sqlite\n .prepare(`SELECT id FROM execution_runs WHERE id = ?`)\n .get(runId) as { id: string } | undefined;\n\n if (!runExists) {\n throw new Error(`Execution run not found: ${runId}`);\n }\n\n ensureValidItemStatus(input.status);\n const id = input.id ?? randomUUID();\n const executedAt = input.executedAt ?? Date.now();\n\n sqlite\n .prepare(\n `\n INSERT INTO execution_items (\n id, run_id, email_id, status, applied_actions, before_label_ids,\n after_label_ids, error_message, executed_at, undone_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `,\n )\n .run(\n id,\n runId,\n input.emailId,\n input.status,\n serializeJson(input.appliedActions ?? []),\n serializeJson(input.beforeLabelIds),\n serializeJson(input.afterLabelIds),\n input.errorMessage ?? null,\n executedAt,\n input.undoneAt ?? null,\n );\n\n const item = sqlite\n .prepare(\n `\n SELECT\n id,\n run_id AS runId,\n email_id AS emailId,\n status,\n applied_actions AS appliedActions,\n before_label_ids AS beforeLabelIds,\n after_label_ids AS afterLabelIds,\n error_message AS errorMessage,\n executed_at AS executedAt,\n undone_at AS undoneAt\n FROM execution_items\n WHERE id = ?\n `,\n )\n .get(id) as Parameters<typeof rowToExecutionItem>[0] | undefined;\n\n if (!item) {\n throw new Error(`Failed to load inserted execution item: ${id}`);\n }\n\n return rowToExecutionItem(item);\n}\n\nexport async function addExecutionItems(\n runId: string,\n items: AppendExecutionItemInput[],\n): Promise<ExecutionItemRecord[]> {\n const inserted: ExecutionItemRecord[] = [];\n\n for (const item of items) {\n inserted.push(await appendExecutionItem(runId, item));\n }\n\n return inserted;\n}\n\nexport async function getRecentRuns(limit: number = 20): Promise<ExecutionRunRecord[]> {\n if (!Number.isInteger(limit) || limit <= 0) {\n throw new Error(`Invalid limit: ${limit}`);\n }\n\n return queryRuns(\"\", [], limit);\n}\n\nexport async function getRun(runId: string): Promise<ExecutionRunRecord | null> {\n const runs = queryRuns(\"WHERE r.id = ?\", [runId], 1);\n return runs[0] ?? null;\n}\n\nexport async function getRunItems(runId: string): Promise<ExecutionItemRecord[]> {\n const sqlite = getDatabase();\n const rows = sqlite\n .prepare(\n `\n SELECT\n id,\n run_id AS runId,\n email_id AS emailId,\n status,\n applied_actions AS appliedActions,\n before_label_ids AS beforeLabelIds,\n after_label_ids AS afterLabelIds,\n error_message AS errorMessage,\n executed_at AS executedAt,\n undone_at AS undoneAt\n FROM execution_items\n WHERE run_id = ?\n ORDER BY COALESCE(executed_at, 0) ASC, id ASC\n `,\n )\n .all(runId) as Parameters<typeof rowToExecutionItem>[0][];\n\n return rows.map(rowToExecutionItem);\n}\n\nexport async function getRunsByEmail(emailId: string): Promise<ExecutionRunRecord[]> {\n return queryRuns(\n \"WHERE EXISTS (SELECT 1 FROM execution_items i2 WHERE i2.run_id = r.id AND i2.email_id = ?)\",\n [emailId],\n );\n}\n\nexport async function getRunsByRule(ruleId: string): Promise<ExecutionRunRecord[]> {\n return queryRuns(\"WHERE r.rule_id = ?\", [ruleId]);\n}\n","import { config as dotenvConfig } from \"dotenv\";\nimport { existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\n\ndotenvConfig();\n\nexport const DEFAULT_GOOGLE_REDIRECT_URI = \"http://127.0.0.1:3456/callback\";\n\ninterface FileConfig {\n dataDir?: string;\n dbPath?: string;\n rulesDir?: string;\n tokensPath?: string;\n google?: {\n clientId?: string;\n clientSecret?: string;\n redirectUri?: string;\n };\n sync?: {\n pageSize?: number;\n maxMessages?: number | null;\n };\n}\n\nexport interface Config {\n dataDir: string;\n dbPath: string;\n rulesDir: string;\n tokensPath: string;\n google: {\n clientId: string | null;\n clientSecret: string | null;\n redirectUri?: string;\n };\n sync: {\n pageSize: number;\n maxMessages: number | null;\n };\n}\n\nexport interface GoogleCredentialStatus {\n configured: boolean;\n missing: string[];\n}\n\nexport function resolveHome(filepath: string): string {\n if (filepath.startsWith(\"~\")) {\n return join(homedir(), filepath.slice(1));\n }\n return filepath;\n}\n\nexport function ensureDir(dir: string): void {\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction readJsonConfig(configPath: string): FileConfig {\n if (!existsSync(configPath)) {\n return {};\n }\n\n const raw = readFileSync(configPath, \"utf8\");\n const parsed = JSON.parse(raw) as unknown;\n\n if (!parsed || typeof parsed !== \"object\") {\n throw new Error(`Invalid config file at ${configPath}: expected JSON object`);\n }\n\n return parsed as FileConfig;\n}\n\nfunction parseNumber(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const parsed = Number(value);\n\n if (Number.isNaN(parsed)) {\n throw new Error(`Invalid numeric configuration value: ${value}`);\n }\n\n return parsed;\n}\n\nfunction resolvePath(value: string | undefined, baseDir: string): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const expanded = resolveHome(value);\n return isAbsolute(expanded) ? expanded : resolve(baseDir, expanded);\n}\n\nexport function getDefaultDataDir(): string {\n return resolveHome(process.env.INBOXCTL_DATA_DIR || \"~/.config/inboxctl\");\n}\n\nexport function getConfigFilePath(dataDir: string = getDefaultDataDir()): string {\n return join(dataDir, \"config.json\");\n}\n\nexport function getGoogleCredentialStatus(config: Config): GoogleCredentialStatus {\n const missing: string[] = [];\n\n if (!config.google.clientId) {\n missing.push(\"GOOGLE_CLIENT_ID\");\n }\n\n if (!config.google.clientSecret) {\n missing.push(\"GOOGLE_CLIENT_SECRET\");\n }\n\n return {\n configured: missing.length === 0,\n missing,\n };\n}\n\nexport function requireGoogleCredentials(config: Config): {\n clientId: string;\n clientSecret: string;\n redirectUri?: string;\n} {\n const status = getGoogleCredentialStatus(config);\n\n if (!status.configured) {\n throw new Error(\n `Missing Google OAuth credentials: ${status.missing.join(\", \")}. ` +\n \"Set them in the environment or in config.json before live Gmail operations.\",\n );\n }\n\n return {\n clientId: config.google.clientId as string,\n clientSecret: config.google.clientSecret as string,\n redirectUri: config.google.redirectUri,\n };\n}\n\nexport function loadConfig(): Config {\n const dataDir = getDefaultDataDir();\n\n ensureDir(dataDir);\n const fileConfig = readJsonConfig(getConfigFilePath(dataDir));\n const configBaseDir = dirname(getConfigFilePath(dataDir));\n\n const dbPath =\n resolvePath(process.env.INBOXCTL_DB_PATH, configBaseDir) ||\n resolvePath(fileConfig.dbPath, configBaseDir) ||\n join(dataDir, \"emails.db\");\n const tokensPath =\n resolvePath(process.env.INBOXCTL_TOKENS_PATH, configBaseDir) ||\n resolvePath(fileConfig.tokensPath, configBaseDir) ||\n join(dataDir, \"tokens.json\");\n const rulesDir =\n resolvePath(process.env.INBOXCTL_RULES_DIR, configBaseDir) ||\n resolvePath(fileConfig.rulesDir, configBaseDir) ||\n resolve(\"./rules\");\n\n ensureDir(dirname(dbPath));\n ensureDir(dirname(tokensPath));\n ensureDir(rulesDir);\n\n return {\n dataDir,\n dbPath,\n rulesDir,\n tokensPath,\n google: {\n clientId:\n process.env.GOOGLE_CLIENT_ID || fileConfig.google?.clientId || null,\n clientSecret:\n process.env.GOOGLE_CLIENT_SECRET ||\n fileConfig.google?.clientSecret ||\n null,\n redirectUri:\n process.env.GOOGLE_REDIRECT_URI ||\n fileConfig.google?.redirectUri ||\n DEFAULT_GOOGLE_REDIRECT_URI,\n },\n sync: {\n pageSize:\n parseNumber(process.env.INBOXCTL_SYNC_PAGE_SIZE) ||\n fileConfig.sync?.pageSize ||\n 500,\n maxMessages:\n parseNumber(process.env.INBOXCTL_SYNC_MAX_MESSAGES) ??\n fileConfig.sync?.maxMessages ??\n null,\n },\n };\n}\n","import Database from \"better-sqlite3\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { dirname, resolve } from \"node:path\";\nimport { ensureDir } from \"../../config.js\";\nimport * as schema from \"./schema.js\";\n\nconst dbCache = new Map<string, ReturnType<typeof drizzle>>();\nconst sqliteCache = new Map<string, Database.Database>();\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS emails (\n id TEXT PRIMARY KEY,\n thread_id TEXT,\n from_address TEXT,\n from_name TEXT,\n to_addresses TEXT,\n subject TEXT,\n snippet TEXT,\n date INTEGER,\n is_read INTEGER,\n is_starred INTEGER,\n label_ids TEXT,\n size_estimate INTEGER,\n has_attachments INTEGER,\n list_unsubscribe TEXT,\n synced_at INTEGER\n);\n\nCREATE INDEX IF NOT EXISTS idx_emails_from_address ON emails(from_address);\nCREATE INDEX IF NOT EXISTS idx_emails_date ON emails(date);\nCREATE INDEX IF NOT EXISTS idx_emails_thread_id ON emails(thread_id);\nCREATE INDEX IF NOT EXISTS idx_emails_is_read ON emails(is_read);\n\nCREATE TABLE IF NOT EXISTS rules (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n description TEXT,\n enabled INTEGER DEFAULT 1,\n yaml_hash TEXT,\n conditions TEXT NOT NULL,\n actions TEXT NOT NULL,\n priority INTEGER DEFAULT 50,\n deployed_at INTEGER,\n created_at INTEGER\n);\n\nCREATE TABLE IF NOT EXISTS execution_runs (\n id TEXT PRIMARY KEY,\n source_type TEXT NOT NULL,\n rule_id TEXT,\n dry_run INTEGER DEFAULT 0,\n requested_actions TEXT NOT NULL,\n query TEXT,\n status TEXT NOT NULL,\n created_at INTEGER,\n undone_at INTEGER\n);\n\nCREATE INDEX IF NOT EXISTS idx_execution_runs_rule_id ON execution_runs(rule_id);\nCREATE INDEX IF NOT EXISTS idx_execution_runs_created_at ON execution_runs(created_at);\n\nCREATE TABLE IF NOT EXISTS execution_items (\n id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL,\n email_id TEXT NOT NULL,\n status TEXT NOT NULL,\n applied_actions TEXT NOT NULL,\n before_label_ids TEXT NOT NULL,\n after_label_ids TEXT NOT NULL,\n error_message TEXT,\n executed_at INTEGER,\n undone_at INTEGER\n);\n\nCREATE INDEX IF NOT EXISTS idx_execution_items_run_id ON execution_items(run_id);\nCREATE INDEX IF NOT EXISTS idx_execution_items_email_id ON execution_items(email_id);\nCREATE INDEX IF NOT EXISTS idx_execution_items_executed_at ON execution_items(executed_at);\n\nCREATE TABLE IF NOT EXISTS sync_state (\n id INTEGER PRIMARY KEY,\n account_email TEXT,\n history_id TEXT,\n last_full_sync INTEGER,\n last_incremental_sync INTEGER,\n total_messages INTEGER,\n full_sync_cursor TEXT,\n full_sync_processed INTEGER,\n full_sync_total INTEGER\n);\n\nCREATE TABLE IF NOT EXISTS newsletter_senders (\n id TEXT PRIMARY KEY,\n email TEXT NOT NULL UNIQUE,\n name TEXT,\n message_count INTEGER DEFAULT 0,\n unread_count INTEGER DEFAULT 0,\n status TEXT DEFAULT 'active',\n unsubscribe_link TEXT,\n detection_reason TEXT,\n first_seen INTEGER,\n last_seen INTEGER\n);\n\nCREATE INDEX IF NOT EXISTS idx_newsletter_senders_email ON newsletter_senders(email);\n\nINSERT OR IGNORE INTO sync_state (id, history_id, last_full_sync, last_incremental_sync, total_messages)\nVALUES (1, NULL, NULL, NULL, 0);\n`;\n\nfunction ensureSyncStateColumns(sqlite: Database.Database): void {\n const columns = sqlite\n .prepare(\"PRAGMA table_info(sync_state)\")\n .all() as Array<{ name: string }>;\n\n const columnNames = new Set(columns.map((column) => column.name));\n\n if (!columnNames.has(\"account_email\")) {\n sqlite.exec(\"ALTER TABLE sync_state ADD COLUMN account_email TEXT\");\n }\n\n if (!columnNames.has(\"full_sync_cursor\")) {\n sqlite.exec(\"ALTER TABLE sync_state ADD COLUMN full_sync_cursor TEXT\");\n }\n\n if (!columnNames.has(\"full_sync_processed\")) {\n sqlite.exec(\"ALTER TABLE sync_state ADD COLUMN full_sync_processed INTEGER\");\n }\n\n if (!columnNames.has(\"full_sync_total\")) {\n sqlite.exec(\"ALTER TABLE sync_state ADD COLUMN full_sync_total INTEGER\");\n }\n}\n\nfunction getResolvedPath(dbPath: string): string {\n return resolve(dbPath);\n}\n\nexport function getSqlite(dbPath: string): Database.Database {\n const resolvedPath = getResolvedPath(dbPath);\n const cached = sqliteCache.get(resolvedPath);\n\n if (cached) {\n return cached;\n }\n\n ensureDir(dirname(resolvedPath));\n const sqlite = new Database(resolvedPath);\n sqlite.pragma(\"journal_mode = WAL\");\n sqlite.pragma(\"foreign_keys = ON\");\n sqlite.pragma(\"busy_timeout = 5000\");\n sqlite.exec(SCHEMA_SQL);\n ensureSyncStateColumns(sqlite);\n sqliteCache.set(resolvedPath, sqlite);\n\n return sqlite;\n}\n\nexport function getDb(dbPath: string) {\n const resolvedPath = getResolvedPath(dbPath);\n const cached = dbCache.get(resolvedPath);\n\n if (cached) {\n return cached;\n }\n\n const sqlite = getSqlite(resolvedPath);\n const db = drizzle(sqlite, { schema });\n dbCache.set(resolvedPath, db);\n\n return db;\n}\n\nexport function initializeDb(dbPath: string) {\n return getDb(dbPath);\n}\n\nexport function closeDb(dbPath: string): void {\n const resolvedPath = getResolvedPath(dbPath);\n const sqlite = sqliteCache.get(resolvedPath);\n\n if (sqlite) {\n sqlite.close();\n sqliteCache.delete(resolvedPath);\n }\n\n dbCache.delete(resolvedPath);\n}\n\nexport function closeAllDbs(): void {\n for (const sqlite of sqliteCache.values()) {\n sqlite.close();\n }\n\n sqliteCache.clear();\n dbCache.clear();\n}\n\nexport type InboxctlDb = ReturnType<typeof getDb>;\n","import { sqliteTable, text, integer, index } from \"drizzle-orm/sqlite-core\";\n\n// --- emails ---\n// Cached email metadata synced from Gmail\nexport const emails = sqliteTable(\n \"emails\",\n {\n id: text(\"id\").primaryKey(), // Gmail message ID\n threadId: text(\"thread_id\"),\n fromAddress: text(\"from_address\"),\n fromName: text(\"from_name\"),\n toAddresses: text(\"to_addresses\"), // JSON array\n subject: text(\"subject\"),\n snippet: text(\"snippet\"),\n date: integer(\"date\"), // Unix timestamp\n isRead: integer(\"is_read\"), // 0/1\n isStarred: integer(\"is_starred\"), // 0/1\n labelIds: text(\"label_ids\"), // JSON array\n sizeEstimate: integer(\"size_estimate\"),\n hasAttachments: integer(\"has_attachments\"), // 0/1\n listUnsubscribe: text(\"list_unsubscribe\"), // List-Unsubscribe header\n syncedAt: integer(\"synced_at\"), // Unix timestamp\n },\n (table) => [\n index(\"idx_emails_from_address\").on(table.fromAddress),\n index(\"idx_emails_date\").on(table.date),\n index(\"idx_emails_thread_id\").on(table.threadId),\n index(\"idx_emails_is_read\").on(table.isRead),\n ],\n);\n\n// --- rules ---\n// Deployed rule definitions (mirrors YAML source files)\nexport const rules = sqliteTable(\"rules\", {\n id: text(\"id\").primaryKey(), // UUID\n name: text(\"name\").unique().notNull(),\n description: text(\"description\"),\n enabled: integer(\"enabled\").default(1), // 0/1\n yamlHash: text(\"yaml_hash\"), // SHA-256 of source YAML\n conditions: text(\"conditions\").notNull(), // JSON\n actions: text(\"actions\").notNull(), // JSON\n priority: integer(\"priority\").default(50),\n deployedAt: integer(\"deployed_at\"),\n createdAt: integer(\"created_at\"),\n});\n\n// --- execution_runs ---\n// Parent audit record for each manual batch or rule run\nexport const executionRuns = sqliteTable(\n \"execution_runs\",\n {\n id: text(\"id\").primaryKey(), // UUID\n sourceType: text(\"source_type\").notNull(), // manual | rule\n ruleId: text(\"rule_id\"), // FK to rules.id (null for manual actions)\n dryRun: integer(\"dry_run\").default(0), // 0/1\n requestedActions: text(\"requested_actions\").notNull(), // JSON\n query: text(\"query\"),\n status: text(\"status\").notNull(), // planned | applied | partial | error | undone\n createdAt: integer(\"created_at\"),\n undoneAt: integer(\"undone_at\"),\n },\n (table) => [\n index(\"idx_execution_runs_rule_id\").on(table.ruleId),\n index(\"idx_execution_runs_created_at\").on(table.createdAt),\n ],\n);\n\n// --- execution_items ---\n// Per-email outcomes within an execution run\nexport const executionItems = sqliteTable(\n \"execution_items\",\n {\n id: text(\"id\").primaryKey(), // UUID\n runId: text(\"run_id\").notNull(), // FK to execution_runs.id\n emailId: text(\"email_id\").notNull(), // Gmail message ID\n status: text(\"status\").notNull(), // planned | applied | warning | error | undone\n appliedActions: text(\"applied_actions\").notNull(), // JSON\n beforeLabelIds: text(\"before_label_ids\").notNull(), // JSON array\n afterLabelIds: text(\"after_label_ids\").notNull(), // JSON array\n errorMessage: text(\"error_message\"),\n executedAt: integer(\"executed_at\"),\n undoneAt: integer(\"undone_at\"),\n },\n (table) => [\n index(\"idx_execution_items_run_id\").on(table.runId),\n index(\"idx_execution_items_email_id\").on(table.emailId),\n index(\"idx_execution_items_executed_at\").on(table.executedAt),\n ],\n);\n\n// --- sync_state ---\n// Singleton tracking Gmail sync progress\nexport const syncState = sqliteTable(\"sync_state\", {\n id: integer(\"id\").primaryKey(), // Always 1\n accountEmail: text(\"account_email\"),\n historyId: text(\"history_id\"),\n lastFullSync: integer(\"last_full_sync\"),\n lastIncrementalSync: integer(\"last_incremental_sync\"),\n totalMessages: integer(\"total_messages\"),\n fullSyncCursor: text(\"full_sync_cursor\"),\n fullSyncProcessed: integer(\"full_sync_processed\"),\n fullSyncTotal: integer(\"full_sync_total\"),\n});\n\n// --- newsletter_senders ---\n// Detected mailing lists and their status\nexport const newsletterSenders = sqliteTable(\n \"newsletter_senders\",\n {\n id: text(\"id\").primaryKey(), // UUID\n email: text(\"email\").unique().notNull(),\n name: text(\"name\"),\n messageCount: integer(\"message_count\").default(0),\n unreadCount: integer(\"unread_count\").default(0),\n status: text(\"status\").default(\"active\"), // active | unsubscribed | archived\n unsubscribeLink: text(\"unsubscribe_link\"),\n detectionReason: text(\"detection_reason\"),\n firstSeen: integer(\"first_seen\"),\n lastSeen: integer(\"last_seen\"),\n },\n (table) => [index(\"idx_newsletter_senders_email\").on(table.email)],\n);\n","import { gmail, type gmail_v1 } from \"@googleapis/gmail\";\nimport type { Config } from \"../../config.js\";\nimport { getAuthenticatedOAuthClient } from \"./client.js\";\nimport type { GmailTransport } from \"./transport.js\";\nimport type {\n RawGmailFilter,\n RawGmailFilterAction,\n RawGmailFilterCriteria,\n RawGmailHistoryResponse,\n RawGmailLabel,\n RawGmailListFiltersResponse,\n RawGmailListLabelsResponse,\n RawGmailListMessagesResponse,\n RawGmailMessage,\n RawGmailProfile,\n RawGmailSendMessageResponse,\n RawGmailThread,\n} from \"./types.js\";\n\nexport function createGoogleApiTransport(config: Config): GmailTransport {\n async function getClient() {\n const auth = await getAuthenticatedOAuthClient(config);\n return gmail({\n version: \"v1\",\n auth,\n } as any);\n }\n\n return {\n kind: \"google-api\",\n async getProfile(): Promise<RawGmailProfile> {\n const client = await getClient();\n const response = await client.users.getProfile({ userId: \"me\" });\n return response.data as RawGmailProfile;\n },\n async listLabels(): Promise<RawGmailListLabelsResponse> {\n const client = await getClient();\n const response = await client.users.labels.list({ userId: \"me\" });\n return response.data as RawGmailListLabelsResponse;\n },\n async getLabel(id: string): Promise<RawGmailLabel> {\n const client = await getClient();\n const response = await client.users.labels.get({ userId: \"me\", id });\n return response.data as RawGmailLabel;\n },\n async createLabel(input): Promise<RawGmailLabel> {\n const client = await getClient();\n const response = await client.users.labels.create({\n userId: \"me\",\n requestBody: {\n name: input.name,\n color: input.color,\n type: \"user\",\n } as gmail_v1.Schema$Label,\n });\n return response.data as RawGmailLabel;\n },\n async batchModifyMessages(input): Promise<void> {\n const client = await getClient();\n await client.users.messages.batchModify({\n userId: \"me\",\n requestBody: {\n ids: input.ids,\n addLabelIds: input.addLabelIds,\n removeLabelIds: input.removeLabelIds,\n } as gmail_v1.Schema$BatchModifyMessagesRequest,\n });\n },\n async sendMessage(raw: string): Promise<RawGmailSendMessageResponse> {\n const client = await getClient();\n const response = await client.users.messages.send({\n userId: \"me\",\n requestBody: {\n raw,\n } as gmail_v1.Schema$Message,\n });\n return response.data as RawGmailSendMessageResponse;\n },\n async listMessages(options): Promise<RawGmailListMessagesResponse> {\n const client = await getClient();\n const response = await client.users.messages.list({\n userId: \"me\",\n q: options.query,\n maxResults: options.maxResults,\n pageToken: options.pageToken,\n });\n return response.data as RawGmailListMessagesResponse;\n },\n async getMessage(options): Promise<RawGmailMessage> {\n const client = await getClient();\n const response = await client.users.messages.get({\n userId: \"me\",\n id: options.id,\n format: options.format,\n metadataHeaders: options.metadataHeaders,\n });\n return response.data as RawGmailMessage;\n },\n async getThread(id): Promise<RawGmailThread> {\n const client = await getClient();\n const response = await client.users.threads.get({\n userId: \"me\",\n id,\n format: \"full\",\n });\n return response.data as RawGmailThread;\n },\n async listHistory(options): Promise<RawGmailHistoryResponse> {\n const client = await getClient();\n const response = await client.users.history.list({\n userId: \"me\",\n startHistoryId: options.startHistoryId,\n maxResults: options.maxResults,\n historyTypes: options.historyTypes,\n });\n return response.data as RawGmailHistoryResponse;\n },\n async listFilters(): Promise<RawGmailListFiltersResponse> {\n const client = await getClient();\n const response = await client.users.settings.filters.list({ userId: \"me\" });\n return response.data as RawGmailListFiltersResponse;\n },\n async getFilter(id: string): Promise<RawGmailFilter> {\n const client = await getClient();\n const response = await client.users.settings.filters.get({ userId: \"me\", id });\n return response.data as RawGmailFilter;\n },\n async createFilter(filter: { criteria: RawGmailFilterCriteria; action: RawGmailFilterAction }): Promise<RawGmailFilter> {\n const client = await getClient();\n const response = await client.users.settings.filters.create({\n userId: \"me\",\n requestBody: filter as any,\n });\n return response.data as RawGmailFilter;\n },\n async deleteFilter(id: string): Promise<void> {\n const client = await getClient();\n await client.users.settings.filters.delete({ userId: \"me\", id });\n },\n };\n}\n","import { OAuth2Client } from \"google-auth-library\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nexport interface StoredTokens {\n accessToken: string;\n refreshToken: string;\n expiryDate: number;\n email: string;\n scope?: string;\n tokenType?: string;\n}\n\nexport async function saveTokens(\n tokensPath: string,\n tokens: StoredTokens,\n): Promise<void> {\n await mkdir(dirname(tokensPath), { recursive: true });\n await writeFile(tokensPath, `${JSON.stringify(tokens, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function loadTokens(\n tokensPath: string,\n): Promise<StoredTokens | null> {\n if (!existsSync(tokensPath)) {\n return null;\n }\n\n const raw = await readFile(tokensPath, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<StoredTokens>;\n\n if (\n typeof parsed.accessToken !== \"string\" ||\n typeof parsed.refreshToken !== \"string\" ||\n typeof parsed.expiryDate !== \"number\" ||\n typeof parsed.email !== \"string\"\n ) {\n throw new Error(`Invalid token file at ${tokensPath}`);\n }\n\n return {\n accessToken: parsed.accessToken,\n refreshToken: parsed.refreshToken,\n expiryDate: parsed.expiryDate,\n email: parsed.email,\n scope: parsed.scope,\n tokenType: parsed.tokenType,\n };\n}\n\nexport function isTokenExpired(tokens: StoredTokens, skewMs: number = 60_000): boolean {\n return Date.now() >= tokens.expiryDate - skewMs;\n}\n\nexport async function refreshAccessToken(\n tokens: StoredTokens,\n clientId: string,\n clientSecret: string,\n): Promise<StoredTokens> {\n const client = new OAuth2Client({\n clientId,\n clientSecret,\n });\n\n client.setCredentials({\n access_token: tokens.accessToken,\n refresh_token: tokens.refreshToken,\n expiry_date: tokens.expiryDate,\n });\n\n const { credentials } = await client.refreshAccessToken();\n\n if (!credentials.access_token || !credentials.expiry_date) {\n throw new Error(\"Google token refresh did not return a new access token\");\n }\n\n return {\n ...tokens,\n accessToken: credentials.access_token,\n refreshToken: credentials.refresh_token || tokens.refreshToken,\n expiryDate: credentials.expiry_date,\n scope: credentials.scope || tokens.scope,\n tokenType: credentials.token_type || tokens.tokenType,\n };\n}\n","import { OAuth2Client } from \"google-auth-library\";\nimport { createServer } from \"node:http\";\nimport { URL } from \"node:url\";\nimport type { AddressInfo } from \"node:net\";\nimport open from \"open\";\nimport {\n DEFAULT_GOOGLE_REDIRECT_URI,\n type Config,\n getGoogleCredentialStatus,\n requireGoogleCredentials,\n} from \"../../config.js\";\nimport { saveTokens } from \"./tokens.js\";\n\nexport const GMAIL_SCOPES = [\n \"https://www.googleapis.com/auth/gmail.modify\",\n \"https://www.googleapis.com/auth/gmail.labels\",\n \"https://www.googleapis.com/auth/gmail.settings.basic\",\n \"https://www.googleapis.com/auth/userinfo.email\",\n];\n\nexport interface OAuthReadiness {\n ready: boolean;\n missing: string[];\n}\n\nexport interface OAuthFlowResult {\n email: string;\n redirectUri: string;\n}\n\nexport function getOAuthReadiness(config: Config): OAuthReadiness {\n const status = getGoogleCredentialStatus(config);\n return {\n ready: status.configured,\n missing: status.missing,\n };\n}\n\nexport function createOAuthClient(config: Config, redirectUri?: string): OAuth2Client {\n const credentials = requireGoogleCredentials(config);\n\n return new OAuth2Client({\n clientId: credentials.clientId,\n clientSecret: credentials.clientSecret,\n redirectUri: redirectUri || credentials.redirectUri,\n });\n}\n\nfunction waitForAuthorizationCode(server: ReturnType<typeof createServer>): Promise<string> {\n return new Promise((resolve, reject) => {\n server.on(\"request\", (request, response) => {\n if (!request.url) {\n response.statusCode = 400;\n response.end(\"Missing callback URL.\");\n reject(new Error(\"Missing callback URL.\"));\n return;\n }\n\n const url = new URL(request.url, \"http://127.0.0.1\");\n const error = url.searchParams.get(\"error\");\n const code = url.searchParams.get(\"code\");\n\n if (error) {\n if (error === \"access_denied\") {\n const guidance = [\n \"Google blocked the sign-in. Common causes:\",\n \"\",\n \"- Your Gmail address is not listed as a test user\",\n \" Go to Google Auth Platform > Audience in Cloud Console\",\n \" and add your email under Test Users.\",\n \"\",\n \"- You selected Internal but are using a personal Gmail account\",\n \" Go to Audience and switch User Type to External.\",\n \"\",\n \"- You clicked Cancel on the Google consent page\",\n \" Just retry: inboxctl auth login\",\n ].join(\"\\n\");\n response.statusCode = 403;\n response.end(`Access denied.\\n\\n${guidance}`);\n reject(new Error(`OAuth access denied.\\n\\n${guidance}`));\n return;\n }\n\n response.statusCode = 400;\n response.end(`OAuth failed: ${error}`);\n reject(new Error(`OAuth failed: ${error}`));\n return;\n }\n\n if (!code) {\n response.statusCode = 400;\n response.end(\"Missing OAuth code.\");\n reject(new Error(\"Missing OAuth code.\"));\n return;\n }\n\n response.statusCode = 200;\n response.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n response.end(\"Authentication complete. You can close this tab and return to inboxctl.\");\n resolve(code);\n });\n\n server.on(\"error\", reject);\n });\n}\n\nasync function listen(server: ReturnType<typeof createServer>, port: number): Promise<AddressInfo> {\n return new Promise((resolve, reject) => {\n server.listen(port, \"127.0.0.1\", () => {\n resolve(server.address() as AddressInfo);\n });\n server.on(\"error\", reject);\n });\n}\n\nasync function getAuthenticatedEmail(accessToken: string): Promise<string> {\n const response = await fetch(\"https://gmail.googleapis.com/gmail/v1/users/me/profile\", {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n\n const profile = (await response.json()) as { emailAddress?: string };\n return profile.emailAddress || \"unknown\";\n}\n\nexport async function startOAuthFlow(config: Config): Promise<OAuthFlowResult> {\n const readiness = getOAuthReadiness(config);\n\n if (!readiness.ready) {\n throw new Error(\n `Google OAuth credentials are not configured yet. Missing: ${readiness.missing.join(\", \")}.`,\n );\n }\n\n const requestedRedirectUri = config.google.redirectUri || DEFAULT_GOOGLE_REDIRECT_URI;\n const server = createServer();\n const redirectUrl = new URL(requestedRedirectUri);\n const address = await listen(server, Number(redirectUrl.port) || 80);\n const redirectUri = `${redirectUrl.protocol}//${redirectUrl.hostname}:${address.port}${redirectUrl.pathname}`;\n\n const client = createOAuthClient(config, redirectUri);\n const codePromise = waitForAuthorizationCode(server);\n\n try {\n const authUrl = client.generateAuthUrl({\n access_type: \"offline\",\n prompt: \"consent\",\n scope: GMAIL_SCOPES,\n });\n\n console.log(`Open this URL if your browser does not launch automatically:\\n${authUrl}\\n`);\n await open(authUrl);\n\n const code = await codePromise;\n const { tokens } = await client.getToken(code);\n\n if (!tokens.access_token || !tokens.refresh_token || !tokens.expiry_date) {\n throw new Error(\n \"Google OAuth did not return the access token, refresh token, and expiry date we need.\",\n );\n }\n\n await saveTokens(config.tokensPath, {\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiryDate: tokens.expiry_date,\n email: \"unknown\",\n scope: tokens.scope,\n tokenType: tokens.token_type ?? undefined,\n });\n\n let email = \"unknown\";\n\n try {\n email = await getAuthenticatedEmail(tokens.access_token);\n await saveTokens(config.tokensPath, {\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiryDate: tokens.expiry_date,\n email,\n scope: tokens.scope,\n tokenType: tokens.token_type ?? undefined,\n });\n } catch (error) {\n console.warn(\n `OAuth completed but fetching the Gmail profile failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n\n return {\n email,\n redirectUri,\n };\n } finally {\n await new Promise<void>((resolve) => server.close(() => resolve()));\n }\n}\n","import { OAuth2Client } from \"google-auth-library\";\nimport { type Config, requireGoogleCredentials } from \"../../config.js\";\nimport {\n type StoredTokens,\n isTokenExpired,\n loadTokens,\n refreshAccessToken,\n saveTokens,\n} from \"../auth/tokens.js\";\nimport { createOAuthClient } from \"../auth/oauth.js\";\n\nconst GMAIL_API_BASE_URL = \"https://gmail.googleapis.com/gmail/v1/users/me\";\nconst MAX_GMAIL_RETRIES = 5;\n\nexport interface GmailClientContext {\n accessToken: string;\n tokens: StoredTokens;\n}\n\nexport interface GmailReadiness {\n ready: boolean;\n missing: string[];\n}\n\nexport function getGmailReadiness(\n config: Config,\n tokens: StoredTokens | null,\n): GmailReadiness {\n const missing: string[] = [];\n\n try {\n requireGoogleCredentials(config);\n } catch {\n missing.push(\"google_credentials\");\n }\n\n if (!tokens) {\n missing.push(\"tokens\");\n }\n\n return {\n ready: missing.length === 0,\n missing,\n };\n}\n\nexport async function getAuthenticatedGmailClient(\n config: Config,\n): Promise<GmailClientContext> {\n const tokens = await getAuthenticatedTokens(config);\n\n return {\n accessToken: tokens.accessToken,\n tokens,\n };\n}\n\nexport async function getAuthenticatedTokens(\n config: Config,\n): Promise<StoredTokens> {\n let tokens = await loadTokens(config.tokensPath);\n\n if (!tokens) {\n throw new Error(\"No Gmail tokens found. Run `inboxctl auth login` first.\");\n }\n\n if (isTokenExpired(tokens)) {\n const credentials = requireGoogleCredentials(config);\n tokens = await refreshAccessToken(\n tokens,\n credentials.clientId,\n credentials.clientSecret,\n );\n await saveTokens(config.tokensPath, tokens);\n }\n\n return tokens;\n}\n\nexport async function getAuthenticatedOAuthClient(\n config: Config,\n): Promise<OAuth2Client> {\n const tokens = await getAuthenticatedTokens(config);\n const auth = createOAuthClient(config);\n auth.setCredentials({\n access_token: tokens.accessToken,\n refresh_token: tokens.refreshToken,\n expiry_date: tokens.expiryDate,\n token_type: tokens.tokenType,\n scope: tokens.scope,\n });\n return auth;\n}\n\nexport async function gmailApiRequest<T>(\n config: Config,\n path: string,\n init?: RequestInit,\n): Promise<T> {\n let attempt = 0;\n\n while (true) {\n attempt += 1;\n const { accessToken } = await getAuthenticatedGmailClient(config);\n const response = await fetch(`${GMAIL_API_BASE_URL}${path}`, {\n ...init,\n headers: {\n Authorization: `Bearer ${accessToken}`,\n ...(init?.headers || {}),\n },\n });\n\n if (response.ok) {\n if (response.status === 204) {\n return undefined as T;\n }\n\n const text = await response.text();\n\n if (!text.trim()) {\n return undefined as T;\n }\n\n return JSON.parse(text) as T;\n }\n\n const text = await response.text();\n const retryable =\n response.status === 429 ||\n response.status === 500 ||\n response.status === 502 ||\n response.status === 503 ||\n response.status === 504;\n\n if (retryable && attempt < MAX_GMAIL_RETRIES) {\n const retryAfterHeader = response.headers.get(\"retry-after\");\n const retryAfterSeconds = retryAfterHeader\n ? Number.parseInt(retryAfterHeader, 10)\n : Number.NaN;\n const delayMs = Number.isNaN(retryAfterSeconds)\n ? Math.min(1000 * 2 ** (attempt - 1), 10_000)\n : retryAfterSeconds * 1000;\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n continue;\n }\n\n const error = new Error(\n `Gmail API request failed: ${response.status} ${response.statusText} ${text}`,\n ) as Error & { code?: number; status?: number };\n error.code = response.status;\n error.status = response.status;\n throw error;\n }\n}\n","import type { Config } from \"../../config.js\";\nimport { gmailApiRequest } from \"./client.js\";\nimport type { GmailTransport } from \"./transport.js\";\nimport type {\n RawGmailFilter,\n RawGmailFilterAction,\n RawGmailFilterCriteria,\n RawGmailHistoryResponse,\n RawGmailLabel,\n RawGmailListFiltersResponse,\n RawGmailListLabelsResponse,\n RawGmailListMessagesResponse,\n RawGmailMessage,\n RawGmailProfile,\n RawGmailSendMessageResponse,\n RawGmailThread,\n} from \"./types.js\";\n\nfunction jsonRequestInit(body: unknown): RequestInit {\n return {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(body),\n };\n}\n\nexport function createRestTransport(config: Config): GmailTransport {\n return {\n kind: \"rest\",\n getProfile(): Promise<RawGmailProfile> {\n return gmailApiRequest<RawGmailProfile>(config, \"/profile\");\n },\n listLabels(): Promise<RawGmailListLabelsResponse> {\n return gmailApiRequest<RawGmailListLabelsResponse>(config, \"/labels\");\n },\n getLabel(id: string): Promise<RawGmailLabel> {\n return gmailApiRequest<RawGmailLabel>(config, `/labels/${id}`);\n },\n createLabel(input): Promise<RawGmailLabel> {\n return gmailApiRequest<RawGmailLabel>(\n config,\n \"/labels\",\n jsonRequestInit({\n name: input.name,\n color: input.color,\n type: \"user\",\n }),\n );\n },\n batchModifyMessages(input): Promise<void> {\n return gmailApiRequest<void>(\n config,\n \"/messages/batchModify\",\n jsonRequestInit({\n ids: input.ids,\n addLabelIds: input.addLabelIds,\n removeLabelIds: input.removeLabelIds,\n }),\n );\n },\n sendMessage(raw: string): Promise<RawGmailSendMessageResponse> {\n return gmailApiRequest<RawGmailSendMessageResponse>(\n config,\n \"/messages/send\",\n jsonRequestInit({\n raw,\n }),\n );\n },\n listMessages(options): Promise<RawGmailListMessagesResponse> {\n const params = new URLSearchParams();\n if (options.query) {\n params.set(\"q\", options.query);\n }\n if (options.maxResults) {\n params.set(\"maxResults\", String(options.maxResults));\n }\n if (options.pageToken) {\n params.set(\"pageToken\", options.pageToken);\n }\n const suffix = params.size > 0 ? `?${params.toString()}` : \"\";\n return gmailApiRequest<RawGmailListMessagesResponse>(config, `/messages${suffix}`);\n },\n getMessage(options): Promise<RawGmailMessage> {\n const params = new URLSearchParams();\n if (options.format) {\n params.set(\"format\", options.format);\n }\n for (const header of options.metadataHeaders || []) {\n params.append(\"metadataHeaders\", header);\n }\n const suffix = params.size > 0 ? `?${params.toString()}` : \"\";\n return gmailApiRequest<RawGmailMessage>(config, `/messages/${options.id}${suffix}`);\n },\n getThread(id): Promise<RawGmailThread> {\n return gmailApiRequest<RawGmailThread>(config, `/threads/${id}?format=full`);\n },\n listHistory(options): Promise<RawGmailHistoryResponse> {\n const params = new URLSearchParams({\n startHistoryId: options.startHistoryId,\n maxResults: String(options.maxResults),\n });\n for (const historyType of options.historyTypes) {\n params.append(\"historyTypes\", historyType);\n }\n return gmailApiRequest<RawGmailHistoryResponse>(config, `/history?${params.toString()}`);\n },\n listFilters(): Promise<RawGmailListFiltersResponse> {\n return gmailApiRequest<RawGmailListFiltersResponse>(config, \"/settings/filters\");\n },\n getFilter(id: string): Promise<RawGmailFilter> {\n return gmailApiRequest<RawGmailFilter>(config, `/settings/filters/${id}`);\n },\n createFilter(filter: { criteria: RawGmailFilterCriteria; action: RawGmailFilterAction }): Promise<RawGmailFilter> {\n return gmailApiRequest<RawGmailFilter>(config, \"/settings/filters\", jsonRequestInit(filter));\n },\n deleteFilter(id: string): Promise<void> {\n return gmailApiRequest<void>(config, `/settings/filters/${id}`, { method: \"DELETE\" });\n },\n };\n}\n","import type { Config } from \"../../config.js\";\nimport type {\n RawGmailFilter,\n RawGmailFilterAction,\n RawGmailFilterCriteria,\n RawGmailHistoryResponse,\n RawGmailLabel,\n RawGmailListFiltersResponse,\n RawGmailListLabelsResponse,\n RawGmailListMessagesResponse,\n RawGmailMessage,\n RawGmailProfile,\n RawGmailSendMessageResponse,\n RawGmailThread,\n} from \"./types.js\";\nimport { createGoogleApiTransport } from \"./transport_google_api.js\";\nimport { createRestTransport } from \"./transport_rest.js\";\n\nexport type GmailTransportKind = \"auto\" | \"google-api\" | \"rest\";\n\nexport interface GmailTransport {\n kind: Exclude<GmailTransportKind, \"auto\">;\n getProfile(): Promise<RawGmailProfile>;\n listLabels(): Promise<RawGmailListLabelsResponse>;\n getLabel(id: string): Promise<RawGmailLabel>;\n createLabel(input: {\n name: string;\n color?: RawGmailLabel[\"color\"];\n }): Promise<RawGmailLabel>;\n batchModifyMessages(input: {\n ids: string[];\n addLabelIds?: string[];\n removeLabelIds?: string[];\n }): Promise<void>;\n sendMessage(raw: string): Promise<RawGmailSendMessageResponse>;\n listMessages(options: {\n query?: string;\n maxResults?: number;\n pageToken?: string;\n }): Promise<RawGmailListMessagesResponse>;\n getMessage(options: {\n id: string;\n format?: \"full\" | \"metadata\";\n metadataHeaders?: string[];\n }): Promise<RawGmailMessage>;\n getThread(id: string): Promise<RawGmailThread>;\n listHistory(options: {\n startHistoryId: string;\n maxResults: number;\n historyTypes: string[];\n }): Promise<RawGmailHistoryResponse>;\n listFilters(): Promise<RawGmailListFiltersResponse>;\n getFilter(id: string): Promise<RawGmailFilter>;\n createFilter(filter: {\n criteria: RawGmailFilterCriteria;\n action: RawGmailFilterAction;\n }): Promise<RawGmailFilter>;\n deleteFilter(id: string): Promise<void>;\n}\n\nconst transportKindCache = new Map<string, Exclude<GmailTransportKind, \"auto\">>();\nconst transportOverrides = new Map<\n string,\n GmailTransport | (() => GmailTransport | Promise<GmailTransport>)\n>();\n\nfunction getConfiguredTransportKind(): GmailTransportKind {\n const value = process.env.INBOXCTL_GMAIL_TRANSPORT;\n\n if (value === \"google-api\" || value === \"rest\" || value === \"auto\") {\n return value;\n }\n\n return \"auto\";\n}\n\nfunction isAuthTransportFailure(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n const status = (error as { code?: number; status?: number }).code ||\n (error as { code?: number; status?: number }).status;\n\n return (\n status === 401 ||\n /Login Required/i.test(message) ||\n /UNAUTHENTICATED/i.test(message) ||\n /CREDENTIALS_MISSING/i.test(message)\n );\n}\n\nexport async function getGmailTransport(config: Config): Promise<GmailTransport> {\n const override = transportOverrides.get(config.dataDir);\n\n if (override) {\n return typeof override === \"function\" ? await override() : override;\n }\n\n const configured = getConfiguredTransportKind();\n\n if (configured === \"rest\") {\n return createRestTransport(config);\n }\n\n if (configured === \"google-api\") {\n return createGoogleApiTransport(config);\n }\n\n const cached = transportKindCache.get(config.dataDir);\n\n if (cached === \"rest\") {\n return createRestTransport(config);\n }\n\n if (cached === \"google-api\") {\n return createGoogleApiTransport(config);\n }\n\n const googleTransport = createGoogleApiTransport(config);\n\n try {\n await googleTransport.getProfile();\n transportKindCache.set(config.dataDir, \"google-api\");\n return googleTransport;\n } catch (error) {\n if (!isAuthTransportFailure(error)) {\n throw error;\n }\n\n transportKindCache.set(config.dataDir, \"rest\");\n return createRestTransport(config);\n }\n}\n\nexport function setGmailTransportOverride(\n dataDir: string,\n transport: GmailTransport | (() => GmailTransport | Promise<GmailTransport>),\n): void {\n transportOverrides.set(dataDir, transport);\n transportKindCache.delete(dataDir);\n}\n\nexport function clearGmailTransportOverride(dataDir: string): void {\n transportOverrides.delete(dataDir);\n transportKindCache.delete(dataDir);\n}\n","import { loadConfig } from \"../../config.js\";\nimport { getGmailTransport } from \"./transport.js\";\nimport type {\n EmailDetail,\n EmailMessage,\n RawGmailMessage,\n RawGmailMessagePart,\n RawGmailMessagePartHeader,\n} from \"./types.js\";\n\nconst MESSAGE_FETCH_CONCURRENCY = 5;\n\nexport type BatchGetMessagesProgressCallback = (\n completed: number,\n total: number,\n) => void;\n\nfunction getHeaders(message: RawGmailMessage): RawGmailMessagePartHeader[] {\n return message.payload?.headers || [];\n}\n\nfunction getHeader(message: RawGmailMessage, name: string): string | null {\n const header = getHeaders(message).find(\n (entry) => entry.name?.toLowerCase() === name.toLowerCase(),\n );\n\n return header?.value || null;\n}\n\nfunction parseAddressList(value: string | null): string[] {\n if (!value) {\n return [];\n }\n\n return value\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean)\n .map((part) => {\n const match = part.match(/<([^>]+)>/);\n return match?.[1] || part.replace(/^\"|\"$/g, \"\");\n });\n}\n\nfunction parseFromHeader(value: string | null): {\n fromName: string;\n fromAddress: string;\n} {\n if (!value) {\n return { fromName: \"\", fromAddress: \"\" };\n }\n\n const match = value.match(/^(.*?)(?:\\s*<([^>]+)>)?$/);\n\n if (!match) {\n return { fromName: \"\", fromAddress: value };\n }\n\n const rawName = match[1]?.trim().replace(/^\"|\"$/g, \"\") || \"\";\n const rawAddress = match[2]?.trim() || rawName;\n\n return {\n fromName: rawAddress === rawName ? \"\" : rawName,\n fromAddress: rawAddress,\n };\n}\n\nfunction decodeBase64Url(value: string | null | undefined): string {\n if (!value) {\n return \"\";\n }\n\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n return Buffer.from(normalized, \"base64\").toString(\"utf8\");\n}\n\nfunction findParts(part: RawGmailMessagePart | undefined, mimeType: string): RawGmailMessagePart[] {\n if (!part) {\n return [];\n }\n\n const matches = part.mimeType === mimeType ? [part] : [];\n const nested = (part.parts || []).flatMap((child) => findParts(child, mimeType));\n return [...matches, ...nested];\n}\n\nfunction extractTextBody(message: RawGmailMessage): string {\n const textParts = findParts(message.payload, \"text/plain\");\n const text = textParts.map((part) => decodeBase64Url(part.body?.data)).join(\"\\n\").trim();\n\n if (text) {\n return text;\n }\n\n return decodeBase64Url(message.payload?.body?.data).trim();\n}\n\nfunction extractHtmlBody(message: RawGmailMessage): string | null {\n const html = findParts(message.payload, \"text/html\")\n .map((part) => decodeBase64Url(part.body?.data))\n .join(\"\\n\")\n .trim();\n\n return html || null;\n}\n\nfunction hasAttachments(part: RawGmailMessagePart | undefined): boolean {\n if (!part) {\n return false;\n }\n\n if (part.filename) {\n return true;\n }\n\n return (part.parts || []).some((child) => hasAttachments(child));\n}\n\nexport function parseMessage(message: RawGmailMessage): EmailMessage {\n const { fromName, fromAddress } = parseFromHeader(getHeader(message, \"From\"));\n const dateHeader = getHeader(message, \"Date\");\n const internalDate = message.internalDate ? Number(message.internalDate) : null;\n const parsedDate = dateHeader ? Date.parse(dateHeader) : NaN;\n\n return {\n id: message.id || \"\",\n threadId: message.threadId || \"\",\n fromAddress,\n fromName,\n toAddresses: parseAddressList(getHeader(message, \"To\")),\n subject: getHeader(message, \"Subject\") || \"\",\n snippet: message.snippet || \"\",\n date:\n internalDate && !Number.isNaN(internalDate)\n ? internalDate\n : Number.isNaN(parsedDate)\n ? Date.now()\n : parsedDate,\n isRead: !(message.labelIds || []).includes(\"UNREAD\"),\n isStarred: (message.labelIds || []).includes(\"STARRED\"),\n labelIds: message.labelIds || [],\n sizeEstimate: message.sizeEstimate || 0,\n hasAttachments: hasAttachments(message.payload),\n listUnsubscribe: getHeader(message, \"List-Unsubscribe\"),\n };\n}\n\nexport function parseMessageDetail(message: RawGmailMessage): EmailDetail {\n const base = parseMessage(message);\n const textPlain = extractTextBody(message);\n const bodyHtml = extractHtmlBody(message);\n\n return {\n ...base,\n textPlain,\n body: textPlain || bodyHtml || \"\",\n bodyHtml,\n };\n}\n\nexport async function listMessages(\n query: string,\n maxResults: number = 20,\n): Promise<EmailMessage[]> {\n const config = loadConfig();\n const transport = await getGmailTransport(config);\n const response = await transport.listMessages({\n query,\n maxResults,\n });\n\n const ids = (response.messages || []).map((message) => message.id).filter(Boolean) as string[];\n return batchGetMessages(ids);\n}\n\nexport async function getMessage(\n id: string,\n): Promise<EmailDetail> {\n const config = loadConfig();\n const transport = await getGmailTransport(config);\n const response = await transport.getMessage({\n id,\n format: \"full\",\n });\n\n if (!response.id) {\n throw new Error(`Gmail message not found: ${id}`);\n }\n\n return parseMessageDetail(response);\n}\n\nexport async function batchGetMessages(\n ids: string[],\n onProgress?: BatchGetMessagesProgressCallback,\n): Promise<EmailMessage[]> {\n if (ids.length === 0) {\n return [];\n }\n\n const config = loadConfig();\n const transport = await getGmailTransport(config);\n const pending = ids.map((id, index) => ({ id, index }));\n const messages: Array<EmailMessage | null> = new Array(ids.length).fill(null);\n let completed = 0;\n\n async function worker(): Promise<void> {\n while (pending.length > 0) {\n const next = pending.shift();\n\n if (!next) {\n return;\n }\n\n const response = await transport.getMessage({\n id: next.id,\n format: \"metadata\",\n metadataHeaders: [\"From\", \"To\", \"Subject\", \"Date\", \"List-Unsubscribe\"],\n });\n\n if (!response.id) {\n messages[next.index] = null;\n completed += 1;\n onProgress?.(completed, ids.length);\n continue;\n }\n\n messages[next.index] = parseMessage(response);\n completed += 1;\n onProgress?.(completed, ids.length);\n }\n }\n\n await Promise.all(\n Array.from({\n length: Math.min(MESSAGE_FETCH_CONCURRENCY, ids.length),\n }, () => worker()),\n );\n\n return messages.filter((message): message is EmailMessage => message !== null);\n}\n","import type { Config } from \"../../config.js\";\nimport { loadConfig } from \"../../config.js\";\nimport type { GmailTransport } from \"./transport.js\";\nimport type {\n GmailLabel,\n RawGmailLabel,\n RawGmailLabelColor,\n} from \"./types.js\";\nimport { getGmailTransport } from \"./transport.js\";\n\ninterface LabelContext {\n config: Config;\n transport: GmailTransport;\n}\n\ninterface LabelOptions {\n config?: Config;\n transport?: GmailTransport;\n forceRefresh?: boolean;\n}\n\ninterface LabelCacheEntry {\n labels: GmailLabel[];\n byId: Map<string, GmailLabel>;\n byName: Map<string, GmailLabel>;\n loadedAt: number;\n}\n\nconst SYSTEM_LABEL_ALIASES = new Map<string, string>([\n [\"INBOX\", \"INBOX\"],\n [\"SENT\", \"SENT\"],\n [\"DRAFT\", \"DRAFT\"],\n [\"TRASH\", \"TRASH\"],\n [\"SPAM\", \"SPAM\"],\n [\"STARRED\", \"STARRED\"],\n [\"IMPORTANT\", \"IMPORTANT\"],\n [\"UNREAD\", \"UNREAD\"],\n [\"SNOOZED\", \"SNOOZED\"],\n [\"ALL_MAIL\", \"ALL_MAIL\"],\n [\"CATEGORY_PERSONAL\", \"CATEGORY_PERSONAL\"],\n [\"CATEGORY_SOCIAL\", \"CATEGORY_SOCIAL\"],\n [\"CATEGORY_PROMOTIONS\", \"CATEGORY_PROMOTIONS\"],\n [\"CATEGORY_UPDATES\", \"CATEGORY_UPDATES\"],\n [\"CATEGORY_FORUMS\", \"CATEGORY_FORUMS\"],\n [\"CHAT\", \"CHAT\"],\n]);\n\nconst labelCache = new Map<string, LabelCacheEntry>();\n\nfunction normalizeKey(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction getCacheKey(config: Config): string {\n return config.dataDir;\n}\n\nexport function getCachedLabelName(\n labelId: string,\n config: Config = loadConfig(),\n): string | null {\n return labelCache.get(getCacheKey(config))?.byId.get(labelId)?.name || null;\n}\n\nfunction toLabel(raw: RawGmailLabel): GmailLabel | null {\n const id = raw.id?.trim() || raw.name?.trim();\n const name = raw.name?.trim() || raw.id?.trim();\n\n if (!id || !name) {\n return null;\n }\n\n return {\n id,\n name,\n type: raw.type === \"system\" ? \"system\" : \"user\",\n color: raw.color || null,\n labelListVisibility: raw.labelListVisibility ?? null,\n messageListVisibility: raw.messageListVisibility ?? null,\n messagesTotal: raw.messagesTotal ?? 0,\n messagesUnread: raw.messagesUnread ?? 0,\n threadsTotal: raw.threadsTotal ?? 0,\n threadsUnread: raw.threadsUnread ?? 0,\n };\n}\n\nfunction setCache(config: Config, labels: GmailLabel[]): void {\n const byId = new Map<string, GmailLabel>();\n const byName = new Map<string, GmailLabel>();\n\n for (const label of labels) {\n byId.set(label.id, label);\n byName.set(normalizeKey(label.name), label);\n byName.set(normalizeKey(label.id), label);\n }\n\n labelCache.set(getCacheKey(config), {\n labels,\n byId,\n byName,\n loadedAt: Date.now(),\n });\n}\n\nfunction updateCacheLabel(config: Config, label: GmailLabel): void {\n const key = getCacheKey(config);\n const existing = labelCache.get(key);\n\n if (!existing) {\n setCache(config, [label]);\n return;\n }\n\n const nextLabels = existing.labels.filter((entry) => entry.id !== label.id);\n nextLabels.push(label);\n setCache(config, nextLabels);\n}\n\nasync function resolveContext(options?: LabelOptions): Promise<LabelContext> {\n const config = options?.config || loadConfig();\n const transport = options?.transport || (await getGmailTransport(config));\n return { config, transport };\n}\n\nfunction resolveSystemLabelId(name: string): string | null {\n const normalized = name\n .trim()\n .replace(/[\\s-]+/g, \"_\")\n .toUpperCase();\n\n return SYSTEM_LABEL_ALIASES.get(normalized) || null;\n}\n\nasync function refreshLabels(context: LabelContext): Promise<GmailLabel[]> {\n const response = await context.transport.listLabels();\n const rawLabels = response.labels || [];\n const detailed = await Promise.all(\n rawLabels.map(async (raw) => {\n const id = raw.id?.trim() || raw.name?.trim();\n\n if (!id) {\n return null;\n }\n\n const detailedLabel = await context.transport.getLabel(id);\n return toLabel(detailedLabel);\n }),\n );\n const labels = detailed.filter((label): label is GmailLabel => label !== null);\n setCache(context.config, labels);\n return labels;\n}\n\nasync function getCachedLabels(context: LabelContext, forceRefresh: boolean): Promise<GmailLabel[]> {\n const cached = labelCache.get(getCacheKey(context.config));\n\n if (!forceRefresh && cached) {\n return cached.labels;\n }\n\n return refreshLabels(context);\n}\n\nexport async function syncLabels(options?: LabelOptions): Promise<GmailLabel[]> {\n const context = await resolveContext(options);\n return getCachedLabels(context, options?.forceRefresh ?? false);\n}\n\nexport async function listLabels(options?: Omit<LabelOptions, \"forceRefresh\">): Promise<GmailLabel[]> {\n return syncLabels({ ...options, forceRefresh: true });\n}\n\nexport async function getLabelId(\n name: string,\n options?: Omit<LabelOptions, \"forceRefresh\">,\n): Promise<string | null> {\n const trimmed = name.trim();\n\n if (!trimmed) {\n return null;\n }\n\n const systemLabelId = resolveSystemLabelId(trimmed);\n if (systemLabelId) {\n return systemLabelId;\n }\n\n const context = await resolveContext(options);\n const labels = await getCachedLabels(context, false);\n const key = normalizeKey(trimmed);\n\n for (const label of labels) {\n if (normalizeKey(label.name) === key || normalizeKey(label.id) === key) {\n return label.id;\n }\n }\n\n return null;\n}\n\nexport async function createLabel(\n name: string,\n color?: RawGmailLabelColor,\n options?: Omit<LabelOptions, \"forceRefresh\">,\n): Promise<GmailLabel> {\n const trimmed = name.trim();\n\n if (!trimmed) {\n throw new Error(\"Label name cannot be empty\");\n }\n\n const context = await resolveContext(options);\n const existingId = await getLabelId(trimmed, context);\n\n if (existingId) {\n const refreshed = await context.transport.getLabel(existingId);\n const label = toLabel(refreshed);\n if (!label) {\n throw new Error(`Unable to resolve label details for ${trimmed}`);\n }\n updateCacheLabel(context.config, label);\n return label;\n }\n\n const created = toLabel(\n await context.transport.createLabel({\n name: trimmed,\n color,\n }),\n );\n\n if (!created) {\n throw new Error(`Gmail did not return a usable label for ${trimmed}`);\n }\n\n const detailed = await context.transport.getLabel(created.id).catch(() => created);\n const label = toLabel(detailed) || created;\n updateCacheLabel(context.config, label);\n return label;\n}\n","import type { Config } from \"../../config.js\";\nimport { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport { parseMessage, parseMessageDetail } from \"./messages.js\";\nimport type { GmailTransport } from \"./transport.js\";\nimport { getGmailTransport } from \"./transport.js\";\nimport type {\n EmailMessage,\n GmailModifyAction,\n GmailModifyItemResult,\n GmailModifyResult,\n RawGmailMessage,\n} from \"./types.js\";\nimport { getLabelId } from \"./labels.js\";\nimport type { Action } from \"../rules/types.js\";\n\ninterface ModifyContext {\n config: Config;\n transport: GmailTransport;\n}\n\ninterface ModifyOptions {\n config?: Config;\n transport?: GmailTransport;\n}\n\ninterface EmailRow {\n id: string;\n thread_id: string | null;\n from_address: string | null;\n from_name: string | null;\n to_addresses: string | null;\n subject: string | null;\n snippet: string | null;\n date: number | null;\n is_read: number | null;\n is_starred: number | null;\n label_ids: string | null;\n size_estimate: number | null;\n has_attachments: number | null;\n list_unsubscribe: string | null;\n}\n\ninterface Snapshot {\n email: EmailMessage;\n}\n\nconst MESSAGE_FETCH_HEADERS = [\"From\", \"To\", \"Subject\", \"Date\", \"List-Unsubscribe\"];\n\nfunction now(): number {\n return Date.now();\n}\n\nfunction normalizeLabelIds(labelIds: string[] | null | undefined): string[] {\n return Array.from(new Set((labelIds || []).filter(Boolean)));\n}\n\nfunction rowToEmail(row: EmailRow): EmailMessage {\n return {\n id: row.id,\n threadId: row.thread_id || \"\",\n fromAddress: row.from_address || \"\",\n fromName: row.from_name || \"\",\n toAddresses: row.to_addresses ? (JSON.parse(row.to_addresses) as string[]) : [],\n subject: row.subject || \"\",\n snippet: row.snippet || \"\",\n date: row.date || 0,\n isRead: (row.is_read || 0) === 1,\n isStarred: (row.is_starred || 0) === 1,\n labelIds: row.label_ids ? (JSON.parse(row.label_ids) as string[]) : [],\n sizeEstimate: row.size_estimate || 0,\n hasAttachments: (row.has_attachments || 0) === 1,\n listUnsubscribe: row.list_unsubscribe,\n };\n}\n\nfunction emailToRow(email: EmailMessage): Record<string, string | number | null> {\n return {\n id: email.id,\n thread_id: email.threadId,\n from_address: email.fromAddress,\n from_name: email.fromName,\n to_addresses: JSON.stringify(email.toAddresses),\n subject: email.subject,\n snippet: email.snippet,\n date: email.date,\n is_read: email.isRead ? 1 : 0,\n is_starred: email.isStarred ? 1 : 0,\n label_ids: JSON.stringify(email.labelIds),\n size_estimate: email.sizeEstimate,\n has_attachments: email.hasAttachments ? 1 : 0,\n list_unsubscribe: email.listUnsubscribe,\n synced_at: now(),\n };\n}\n\nfunction applyLabelChange(\n labelIds: string[],\n addLabelIds: string[] = [],\n removeLabelIds: string[] = [],\n): string[] {\n const next = [...labelIds];\n\n for (const labelId of removeLabelIds) {\n const index = next.indexOf(labelId);\n if (index >= 0) {\n next.splice(index, 1);\n }\n }\n\n for (const labelId of addLabelIds) {\n if (!next.includes(labelId)) {\n next.push(labelId);\n }\n }\n\n return next;\n}\n\nfunction getReadState(labelIds: string[]): boolean {\n return !labelIds.includes(\"UNREAD\");\n}\n\nasync function resolveContext(options?: ModifyOptions): Promise<ModifyContext> {\n const config = options?.config || loadConfig();\n const transport = options?.transport || (await getGmailTransport(config));\n return { config, transport };\n}\n\nfunction makePlaceholders(values: string[]): string {\n return values.map(() => \"?\").join(\", \");\n}\n\nfunction readSnapshots(config: Config, ids: string[]): Map<string, Snapshot> {\n const sqlite = getSqlite(config.dbPath);\n const rows = sqlite\n .prepare(\n `\n SELECT id, thread_id, from_address, from_name, to_addresses, subject, snippet, date,\n is_read, is_starred, label_ids, size_estimate, has_attachments, list_unsubscribe\n FROM emails\n WHERE id IN (${makePlaceholders(ids)})\n `,\n )\n .all(...ids) as EmailRow[];\n\n const snapshots = new Map<string, Snapshot>();\n\n for (const row of rows) {\n snapshots.set(row.id, {\n email: rowToEmail(row),\n });\n }\n\n return snapshots;\n}\n\nasync function fetchMissingSnapshots(\n transport: GmailTransport,\n ids: string[],\n snapshots: Map<string, Snapshot>,\n): Promise<void> {\n const missing = ids.filter((id) => !snapshots.has(id));\n\n const fetched = await Promise.all(\n missing.map(async (id) => {\n const response = await transport.getMessage({\n id,\n format: \"metadata\",\n metadataHeaders: MESSAGE_FETCH_HEADERS,\n });\n\n if (!response.id) {\n throw new Error(`Gmail message not found: ${id}`);\n }\n\n return parseMessage(response);\n }),\n );\n\n for (const email of fetched) {\n snapshots.set(email.id, { email });\n }\n}\n\nfunction upsertEmails(config: Config, emails: EmailMessage[]): void {\n if (emails.length === 0) {\n return;\n }\n\n const sqlite = getSqlite(config.dbPath);\n const statement = sqlite.prepare(`\n INSERT INTO emails (\n id, thread_id, from_address, from_name, to_addresses, subject, snippet, date,\n is_read, is_starred, label_ids, size_estimate, has_attachments, list_unsubscribe, synced_at\n ) VALUES (\n @id, @thread_id, @from_address, @from_name, @to_addresses, @subject, @snippet, @date,\n @is_read, @is_starred, @label_ids, @size_estimate, @has_attachments, @list_unsubscribe, @synced_at\n )\n ON CONFLICT(id) DO UPDATE SET\n thread_id = excluded.thread_id,\n from_address = excluded.from_address,\n from_name = excluded.from_name,\n to_addresses = excluded.to_addresses,\n subject = excluded.subject,\n snippet = excluded.snippet,\n date = excluded.date,\n is_read = excluded.is_read,\n is_starred = excluded.is_starred,\n label_ids = excluded.label_ids,\n size_estimate = excluded.size_estimate,\n has_attachments = excluded.has_attachments,\n list_unsubscribe = excluded.list_unsubscribe,\n synced_at = excluded.synced_at\n `);\n\n const transaction = sqlite.transaction((rows: EmailMessage[]) => {\n for (const email of rows) {\n statement.run(emailToRow(email));\n }\n });\n\n transaction(emails);\n}\n\nfunction buildResult(\n action: GmailModifyAction,\n items: GmailModifyItemResult[],\n metadata?: Partial<Pick<GmailModifyResult, \"labelId\" | \"labelName\" | \"toAddress\" | \"sentMessageId\" | \"sentThreadId\">>,\n): GmailModifyResult {\n return {\n action,\n affectedCount: items.length,\n items,\n nonReversible: action === \"forward\",\n ...metadata,\n };\n}\n\nfunction buildAppliedActions(\n action: GmailModifyAction,\n metadata?: Partial<Pick<GmailModifyResult, \"labelName\" | \"toAddress\">>,\n): Action[] {\n switch (action) {\n case \"archive\":\n return [{ type: \"archive\" }];\n case \"label\":\n return metadata?.labelName ? [{ type: \"label\", label: metadata.labelName }] : [];\n case \"mark_read\":\n return [{ type: \"mark_read\" }];\n case \"mark_spam\":\n return [{ type: \"mark_spam\" }];\n case \"forward\":\n return metadata?.toAddress ? [{ type: \"forward\", to: metadata.toAddress }] : [];\n default:\n return [];\n }\n}\n\nasync function performLabelMutation(\n action: Exclude<GmailModifyAction, \"forward\">,\n ids: string[],\n addLabelIds: string[],\n removeLabelIds: string[],\n options?: ModifyOptions,\n metadata?: Partial<Pick<GmailModifyResult, \"labelId\" | \"labelName\">>,\n): Promise<GmailModifyResult> {\n const uniqueIds = Array.from(new Set(ids.filter(Boolean)));\n\n if (uniqueIds.length === 0) {\n return buildResult(action, [], metadata);\n }\n\n const context = await resolveContext(options);\n const snapshots = readSnapshots(context.config, uniqueIds);\n await fetchMissingSnapshots(context.transport, uniqueIds, snapshots);\n\n const orderedSnapshots = uniqueIds.map((id) => {\n const snapshot = snapshots.get(id);\n\n if (!snapshot) {\n throw new Error(`Unable to resolve Gmail message snapshot for ${id}`);\n }\n\n return snapshot;\n });\n\n const batchSize = 1000;\n for (let index = 0; index < uniqueIds.length; index += batchSize) {\n await context.transport.batchModifyMessages({\n ids: uniqueIds.slice(index, index + batchSize),\n addLabelIds,\n removeLabelIds,\n });\n }\n\n const updatedEmails = orderedSnapshots.map(({ email }) => {\n const labelIds = applyLabelChange(email.labelIds, addLabelIds, removeLabelIds);\n return {\n ...email,\n labelIds,\n isRead: getReadState(labelIds),\n };\n });\n\n upsertEmails(context.config, updatedEmails);\n\n const items = orderedSnapshots.map(({ email }, index) => {\n const afterLabelIds = updatedEmails[index]?.labelIds || [];\n return {\n emailId: email.id,\n beforeLabelIds: [...email.labelIds],\n afterLabelIds,\n status: \"applied\" as const,\n appliedActions: buildAppliedActions(action, metadata),\n };\n });\n\n return buildResult(action, items, metadata);\n}\n\nfunction encodeBase64Url(value: string): string {\n return Buffer.from(value, \"utf8\")\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n}\n\nfunction formatAddress(name: string, address: string): string {\n if (!name) {\n return address;\n }\n\n return `\"${name.replace(/\"/g, '\\\\\"')}\" <${address}>`;\n}\n\nfunction normalizeForwardSubject(subject: string): string {\n if (/^fwd:/i.test(subject)) {\n return subject;\n }\n\n return `Fwd: ${subject}`;\n}\n\nfunction buildForwardRawMessage(\n message: RawGmailMessage,\n toAddress: string,\n): { raw: string; detail: ReturnType<typeof parseMessageDetail> } {\n const detail = parseMessageDetail(message);\n const introLines = [\n \"---------- Forwarded message ---------\",\n `From: ${formatAddress(detail.fromName, detail.fromAddress)}`,\n `Date: ${new Date(detail.date).toUTCString()}`,\n `Subject: ${detail.subject}`,\n `To: ${detail.toAddresses.join(\", \")}`,\n \"\",\n ];\n const forwardedBody = detail.body || detail.textPlain || detail.snippet || \"\";\n const rawMessage = [\n `To: ${toAddress}`,\n `Subject: ${normalizeForwardSubject(detail.subject)}`,\n 'Content-Type: text/plain; charset=\"UTF-8\"',\n \"\",\n [...introLines, forwardedBody].join(\"\\r\\n\"),\n ].join(\"\\r\\n\");\n\n return {\n raw: encodeBase64Url(rawMessage),\n detail,\n };\n}\n\nexport interface RestoreEmailLabelsResult {\n status: \"applied\" | \"error\";\n errorMessage?: string | null;\n}\n\nexport async function restoreEmailLabels(\n emailId: string,\n beforeLabelIds: string[],\n): Promise<RestoreEmailLabelsResult> {\n try {\n const context = await resolveContext();\n const snapshots = readSnapshots(context.config, [emailId]);\n await fetchMissingSnapshots(context.transport, [emailId], snapshots);\n\n const snapshot = snapshots.get(emailId);\n\n if (!snapshot) {\n return {\n status: \"error\",\n errorMessage: `Unable to resolve Gmail message snapshot for ${emailId}`,\n };\n }\n\n const currentLabelIds = normalizeLabelIds(snapshot.email.labelIds);\n const targetLabelIds = normalizeLabelIds(beforeLabelIds);\n const addLabelIds = targetLabelIds.filter((labelId) => !currentLabelIds.includes(labelId));\n const removeLabelIds = currentLabelIds.filter((labelId) => !targetLabelIds.includes(labelId));\n\n if (addLabelIds.length === 0 && removeLabelIds.length === 0) {\n return { status: \"applied\" };\n }\n\n await context.transport.batchModifyMessages({\n ids: [emailId],\n addLabelIds,\n removeLabelIds,\n });\n\n const restoredLabelIds = applyLabelChange(currentLabelIds, addLabelIds, removeLabelIds);\n upsertEmails(context.config, [\n {\n ...snapshot.email,\n labelIds: restoredLabelIds,\n isRead: getReadState(restoredLabelIds),\n },\n ]);\n\n return { status: \"applied\" };\n } catch (error) {\n return {\n status: \"error\",\n errorMessage: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport async function archiveEmails(\n ids: string[],\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n return performLabelMutation(\"archive\", ids, [], [\"INBOX\"], options, {\n labelId: \"INBOX\",\n labelName: \"INBOX\",\n });\n}\n\nexport async function unarchiveEmails(\n ids: string[],\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n return performLabelMutation(\"unarchive\", ids, [\"INBOX\"], [], options, {\n labelId: \"INBOX\",\n labelName: \"INBOX\",\n });\n}\n\nexport async function labelEmails(\n ids: string[],\n labelName: string,\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n const context = await resolveContext(options);\n const labelId = await getLabelId(labelName, context);\n\n if (!labelId) {\n throw new Error(`Unknown Gmail label: ${labelName}`);\n }\n\n return performLabelMutation(\"label\", ids, [labelId], [], context, {\n labelId,\n labelName,\n });\n}\n\nexport async function unlabelEmails(\n ids: string[],\n labelName: string,\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n const context = await resolveContext(options);\n const labelId = await getLabelId(labelName, context);\n\n if (!labelId) {\n throw new Error(`Unknown Gmail label: ${labelName}`);\n }\n\n return performLabelMutation(\"unlabel\", ids, [], [labelId], context, {\n labelId,\n labelName,\n });\n}\n\nexport async function markRead(\n ids: string[],\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n return performLabelMutation(\"mark_read\", ids, [], [\"UNREAD\"], options, {\n labelId: \"UNREAD\",\n labelName: \"UNREAD\",\n });\n}\n\nexport async function markUnread(\n ids: string[],\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n return performLabelMutation(\"mark_unread\", ids, [\"UNREAD\"], [], options, {\n labelId: \"UNREAD\",\n labelName: \"UNREAD\",\n });\n}\n\nexport async function markSpam(\n ids: string[],\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n return performLabelMutation(\"mark_spam\", ids, [\"SPAM\"], [\"INBOX\"], options, {\n labelId: \"SPAM\",\n labelName: \"SPAM\",\n });\n}\n\nexport async function unmarkSpam(\n ids: string[],\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n return performLabelMutation(\"unmark_spam\", ids, [\"INBOX\"], [\"SPAM\"], options, {\n labelId: \"SPAM\",\n labelName: \"SPAM\",\n });\n}\n\nexport async function forwardEmail(\n id: string,\n toAddress: string,\n options?: ModifyOptions,\n): Promise<GmailModifyResult> {\n const context = await resolveContext(options);\n const response = await context.transport.getMessage({\n id,\n format: \"full\",\n });\n\n if (!response.id) {\n throw new Error(`Gmail message not found: ${id}`);\n }\n\n const { raw, detail } = buildForwardRawMessage(response, toAddress);\n const sent = await context.transport.sendMessage(raw);\n const labelIds = normalizeLabelIds(response.labelIds || detail.labelIds);\n\n return buildResult(\n \"forward\",\n [\n {\n emailId: response.id,\n beforeLabelIds: labelIds,\n afterLabelIds: labelIds,\n status: \"applied\",\n appliedActions: buildAppliedActions(\"forward\", { toAddress }),\n },\n ],\n {\n toAddress,\n sentMessageId: sent.id || undefined,\n sentThreadId: sent.threadId || undefined,\n },\n );\n}\n","import { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport { restoreEmailLabels } from \"../gmail/modify.js\";\nimport type {\n AuditAction,\n ExecutionItemRecord,\n ExecutionItemStatus,\n ExecutionRunRecord,\n ExecutionRunStatus,\n} from \"./audit.js\";\nimport { getRun, getRunItems } from \"./audit.js\";\n\nexport interface UndoRunResult {\n runId: string;\n run: ExecutionRunRecord;\n warnings: string[];\n restoredItemCount: number;\n itemCount: number;\n undoneCount: number;\n warningCount: number;\n errorCount: number;\n status: ExecutionRunStatus;\n}\n\nfunction getDatabase() {\n const config = loadConfig();\n return getSqlite(config.dbPath);\n}\n\nfunction getActionType(action: AuditAction): string | null {\n return typeof action === \"object\" && action && \"type\" in action && typeof action.type === \"string\"\n ? action.type.toLowerCase()\n : null;\n}\n\nfunction hasNonReversibleAction(item: ExecutionItemRecord): boolean {\n return item.appliedActions.some((action) => getActionType(action) === \"forward\");\n}\n\nfunction updateItem(\n sqlite: ReturnType<typeof getSqlite>,\n itemId: string,\n status: ExecutionItemStatus,\n errorMessage: string | null,\n undoneAt: number | null,\n): void {\n sqlite\n .prepare(\n `\n UPDATE execution_items\n SET status = ?, error_message = ?, undone_at = ?\n WHERE id = ?\n `,\n )\n .run(status, errorMessage, undoneAt, itemId);\n}\n\nfunction updateRun(\n sqlite: ReturnType<typeof getSqlite>,\n runId: string,\n status: ExecutionRunStatus,\n undoneAt: number | null,\n): void {\n sqlite\n .prepare(\n `\n UPDATE execution_runs\n SET status = ?, undone_at = ?\n WHERE id = ?\n `,\n )\n .run(status, undoneAt, runId);\n}\n\nexport async function undoRun(runId: string): Promise<UndoRunResult> {\n const sqlite = getDatabase();\n const run = await getRun(runId);\n\n if (!run) {\n throw new Error(`Execution run not found: ${runId}`);\n }\n\n if (run.status === \"undone\" || run.undoneAt !== null) {\n throw new Error(`Execution run is already undone: ${runId}`);\n }\n\n const items = await getRunItems(runId);\n const warnings: string[] = [];\n let undoneCount = 0;\n let warningCount = 0;\n let errorCount = 0;\n const undoneAt = Date.now();\n\n for (const item of items) {\n const restored = await restoreEmailLabels(item.emailId, item.beforeLabelIds);\n\n if (restored.status === \"error\") {\n errorCount += 1;\n updateItem(\n sqlite,\n item.id,\n \"error\",\n restored.errorMessage || \"Failed to restore Gmail label snapshot.\",\n null,\n );\n continue;\n }\n\n if (hasNonReversibleAction(item)) {\n const message = `Email ${item.emailId}: label state was restored, but forward actions cannot be undone.`;\n warnings.push(message);\n warningCount += 1;\n updateItem(sqlite, item.id, \"warning\", message, undoneAt);\n continue;\n }\n\n undoneCount += 1;\n updateItem(sqlite, item.id, \"undone\", null, undoneAt);\n }\n\n const status: ExecutionRunStatus = errorCount > 0 || warningCount > 0 ? \"partial\" : \"undone\";\n updateRun(sqlite, run.id, status, undoneAt);\n\n const refreshedRun = await getRun(run.id);\n\n if (!refreshedRun) {\n throw new Error(`Failed to reload execution run after undo: ${run.id}`);\n }\n\n return {\n runId: run.id,\n run: refreshedRun,\n warnings,\n restoredItemCount: undoneCount + warningCount,\n itemCount: items.length,\n undoneCount,\n warningCount,\n errorCount,\n status,\n };\n}\n","import { loadConfig } from \"../../config.js\";\nimport { getGmailTransport } from \"./transport.js\";\nimport { parseMessageDetail } from \"./messages.js\";\nimport type { EmailDetail, EmailThread } from \"./types.js\";\n\nexport async function getThread(\n id: string,\n): Promise<EmailThread & { messages: EmailDetail[] }> {\n const config = loadConfig();\n const transport = await getGmailTransport(config);\n const response = await transport.getThread(id);\n\n const messages = (response.messages || []).map((message) =>\n parseMessageDetail(message),\n );\n\n return {\n id: response.id || id,\n messages,\n };\n}\n","import type Database from \"better-sqlite3\";\nimport { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport { getCachedLabelName } from \"../gmail/labels.js\";\n\nexport type StatsPeriod = \"day\" | \"week\" | \"month\" | \"year\" | \"all\";\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nconst SYSTEM_LABEL_NAMES = new Map<string, string>([\n [\"INBOX\", \"Inbox\"],\n [\"UNREAD\", \"Unread\"],\n [\"STARRED\", \"Starred\"],\n [\"IMPORTANT\", \"Important\"],\n [\"SENT\", \"Sent\"],\n [\"DRAFT\", \"Drafts\"],\n [\"TRASH\", \"Trash\"],\n [\"SPAM\", \"Spam\"],\n [\"ALL_MAIL\", \"All Mail\"],\n [\"SNOOZED\", \"Snoozed\"],\n [\"CHAT\", \"Chat\"],\n [\"CATEGORY_PERSONAL\", \"Personal\"],\n [\"CATEGORY_SOCIAL\", \"Social\"],\n [\"CATEGORY_PROMOTIONS\", \"Promotions\"],\n [\"CATEGORY_UPDATES\", \"Updates\"],\n [\"CATEGORY_FORUMS\", \"Forums\"],\n]);\n\nexport function getStatsSqlite(): Database.Database {\n const config = loadConfig();\n return getSqlite(config.dbPath);\n}\n\nexport function normalizeLimit(value: number | undefined, fallback: number): number {\n if (!value || Number.isNaN(value) || value < 1) {\n return fallback;\n }\n\n return Math.floor(value);\n}\n\nexport function clampPercentage(value: number | undefined, fallback: number = 0): number {\n if (value === undefined || Number.isNaN(value)) {\n return fallback;\n }\n\n return Math.max(0, Math.min(100, value));\n}\n\nexport function roundPercent(numerator: number, denominator: number): number {\n if (!denominator) {\n return 0;\n }\n\n return Math.round((numerator / denominator) * 1000) / 10;\n}\n\nexport function getPeriodStart(period: StatsPeriod = \"all\", now: number = Date.now()): number | null {\n switch (period) {\n case \"day\":\n return now - DAY_MS;\n case \"week\":\n return now - 7 * DAY_MS;\n case \"month\":\n return now - 30 * DAY_MS;\n case \"year\":\n return now - 365 * DAY_MS;\n case \"all\":\n return null;\n }\n}\n\nexport function extractDomain(email: string): string | null {\n const trimmed = email.trim().toLowerCase();\n const atIndex = trimmed.lastIndexOf(\"@\");\n\n if (atIndex <= 0 || atIndex === trimmed.length - 1) {\n return null;\n }\n\n return trimmed.slice(atIndex + 1);\n}\n\nexport function resolveLabelName(labelId: string): string {\n return SYSTEM_LABEL_NAMES.get(labelId) || getCachedLabelName(labelId) || labelId;\n}\n\nexport function startOfLocalDay(now: number = Date.now()): number {\n const date = new Date(now);\n date.setHours(0, 0, 0, 0);\n return date.getTime();\n}\n\nexport function startOfLocalWeek(now: number = Date.now()): number {\n const date = new Date(startOfLocalDay(now));\n const day = date.getDay();\n const diff = day === 0 ? 6 : day - 1;\n date.setDate(date.getDate() - diff);\n return date.getTime();\n}\n\nexport function startOfLocalMonth(now: number = Date.now()): number {\n const date = new Date(now);\n date.setDate(1);\n date.setHours(0, 0, 0, 0);\n return date.getTime();\n}\n","import { getStatsSqlite, resolveLabelName } from \"./common.js\";\n\nexport interface LabelStat {\n labelId: string;\n labelName: string;\n totalMessages: number;\n unreadMessages: number;\n}\n\ninterface LabelRow {\n labelId: string;\n totalMessages: number;\n unreadMessages: number;\n}\n\nexport async function getLabelDistribution(): Promise<LabelStat[]> {\n const sqlite = getStatsSqlite();\n const rows = sqlite\n .prepare(\n `\n SELECT\n label.value AS labelId,\n COUNT(*) AS totalMessages,\n SUM(CASE WHEN e.is_read = 0 THEN 1 ELSE 0 END) AS unreadMessages\n FROM emails AS e, json_each(e.label_ids) AS label\n GROUP BY label.value\n ORDER BY totalMessages DESC, unreadMessages DESC, label.value ASC\n `,\n )\n .all() as LabelRow[];\n\n return rows.map((row) => ({\n labelId: row.labelId,\n labelName: resolveLabelName(row.labelId),\n totalMessages: row.totalMessages,\n unreadMessages: row.unreadMessages,\n }));\n}\n","import { randomUUID } from \"node:crypto\";\nimport {\n clampPercentage,\n getStatsSqlite,\n normalizeLimit,\n roundPercent,\n} from \"./common.js\";\n\nexport type NewsletterStatus = \"active\" | \"unsubscribed\" | \"archived\";\n\nexport interface NewsletterOptions {\n minMessages?: number;\n minUnreadRate?: number;\n status?: NewsletterStatus | \"all\";\n}\n\nexport interface NewsletterSender {\n email: string;\n name: string;\n messageCount: number;\n unreadCount: number;\n unreadRate: number;\n status: NewsletterStatus;\n unsubscribeLink: string | null;\n firstSeen: Date;\n lastSeen: Date;\n detectionReason: string;\n}\n\ninterface NewsletterAggregateRow {\n email: string;\n name: string | null;\n messageCount: number;\n unreadCount: number;\n firstSeen: number;\n lastSeen: number;\n unsubscribeLink: string | null;\n recipientPatternCount: number;\n}\n\ninterface NewsletterRow {\n email: string;\n name: string | null;\n messageCount: number;\n unreadCount: number;\n status: NewsletterStatus;\n unsubscribeLink: string | null;\n firstSeen: number;\n lastSeen: number;\n detectionReason: string;\n}\n\ninterface DetectedNewsletterRow {\n id: string;\n email: string;\n name: string;\n messageCount: number;\n unreadCount: number;\n unsubscribeLink: string | null;\n detectionReason: string;\n firstSeen: number;\n lastSeen: number;\n}\n\nconst KNOWN_NEWSLETTER_LOCAL_PART =\n /^(newsletter|digest|noreply|no-reply|updates|news)([+._-].*)?$/i;\n\nfunction extractNewsletterReasons(row: NewsletterAggregateRow): string[] {\n const reasons: string[] = [];\n const localPart = row.email.split(\"@\")[0] || \"\";\n const unreadRate = roundPercent(row.unreadCount, row.messageCount);\n\n if (row.unsubscribeLink) {\n reasons.push(\"list_unsubscribe\");\n }\n\n if (row.messageCount > 5 && unreadRate > 50) {\n reasons.push(\"high_volume_high_unread\");\n }\n\n if (KNOWN_NEWSLETTER_LOCAL_PART.test(localPart)) {\n reasons.push(\"known_sender_pattern\");\n }\n\n if (row.recipientPatternCount > 1) {\n reasons.push(\"bulk_sender_pattern\");\n }\n\n return reasons;\n}\n\nfunction normalizeUnsubscribeLink(value: string | null): string | null {\n if (!value) {\n return null;\n }\n\n const header = value.trim();\n const match = header.match(/<([^>]+)>/);\n\n return match?.[1]?.trim() || header.split(\",\")[0]?.trim() || null;\n}\n\nfunction mapNewsletterRow(row: NewsletterRow): NewsletterSender {\n return {\n email: row.email,\n name: row.name?.trim() || row.email,\n messageCount: row.messageCount,\n unreadCount: row.unreadCount,\n unreadRate: roundPercent(row.unreadCount, row.messageCount),\n status: row.status,\n unsubscribeLink: row.unsubscribeLink,\n firstSeen: new Date(row.firstSeen),\n lastSeen: new Date(row.lastSeen),\n detectionReason: row.detectionReason,\n };\n}\n\nexport async function detectNewsletters(): Promise<NewsletterSender[]> {\n const sqlite = getStatsSqlite();\n const rows = sqlite\n .prepare(\n `\n SELECT\n from_address AS email,\n COALESCE(MAX(NULLIF(TRIM(from_name), '')), from_address) AS name,\n COUNT(*) AS messageCount,\n SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) AS unreadCount,\n MIN(date) AS firstSeen,\n MAX(date) AS lastSeen,\n MAX(NULLIF(TRIM(list_unsubscribe), '')) AS unsubscribeLink,\n COUNT(DISTINCT to_addresses) AS recipientPatternCount\n FROM emails\n WHERE from_address IS NOT NULL\n AND TRIM(from_address) <> ''\n GROUP BY from_address\n `,\n )\n .all() as NewsletterAggregateRow[];\n\n const detected: DetectedNewsletterRow[] = [];\n\n for (const row of rows) {\n const reasons = extractNewsletterReasons(row);\n\n if (reasons.length === 0) {\n continue;\n }\n\n detected.push({\n id: randomUUID(),\n email: row.email,\n name: row.name?.trim() || row.email,\n messageCount: row.messageCount,\n unreadCount: row.unreadCount,\n unsubscribeLink: normalizeUnsubscribeLink(row.unsubscribeLink),\n detectionReason: reasons.join(\", \"),\n firstSeen: row.firstSeen,\n lastSeen: row.lastSeen,\n });\n }\n\n const upsert = sqlite.prepare(\n `\n INSERT INTO newsletter_senders (\n id,\n email,\n name,\n message_count,\n unread_count,\n status,\n unsubscribe_link,\n detection_reason,\n first_seen,\n last_seen\n ) VALUES (?, ?, ?, ?, ?, 'active', ?, ?, ?, ?)\n ON CONFLICT(email) DO UPDATE SET\n name = excluded.name,\n message_count = excluded.message_count,\n unread_count = excluded.unread_count,\n unsubscribe_link = excluded.unsubscribe_link,\n detection_reason = excluded.detection_reason,\n first_seen = excluded.first_seen,\n last_seen = excluded.last_seen\n `,\n );\n\n const transaction = sqlite.transaction(\n (\n entries: DetectedNewsletterRow[],\n ) => {\n for (const entry of entries) {\n upsert.run(\n entry.id,\n entry.email,\n entry.name,\n entry.messageCount,\n entry.unreadCount,\n entry.unsubscribeLink,\n entry.detectionReason,\n entry.firstSeen,\n entry.lastSeen,\n );\n }\n },\n );\n\n transaction(detected);\n\n return detected.map((row) => ({\n email: row.email,\n name: row.name,\n messageCount: row.messageCount,\n unreadCount: row.unreadCount,\n unreadRate: roundPercent(row.unreadCount, row.messageCount),\n status: \"active\",\n unsubscribeLink: row.unsubscribeLink,\n firstSeen: new Date(row.firstSeen),\n lastSeen: new Date(row.lastSeen),\n detectionReason: row.detectionReason,\n }));\n}\n\nexport async function getNewsletters(\n options: NewsletterOptions = {},\n): Promise<NewsletterSender[]> {\n await detectNewsletters();\n\n const sqlite = getStatsSqlite();\n const minMessages = normalizeLimit(options.minMessages, 1);\n const minUnreadRate = clampPercentage(options.minUnreadRate, 0);\n const status = options.status || \"active\";\n\n const rows = sqlite\n .prepare(\n `\n SELECT\n email,\n name,\n message_count AS messageCount,\n unread_count AS unreadCount,\n status,\n unsubscribe_link AS unsubscribeLink,\n first_seen AS firstSeen,\n last_seen AS lastSeen,\n detection_reason AS detectionReason\n FROM newsletter_senders\n WHERE message_count >= ?\n AND (100.0 * unread_count / CASE WHEN message_count = 0 THEN 1 ELSE message_count END) >= ?\n AND (? = 'all' OR status = ?)\n ORDER BY message_count DESC, unreadCount DESC, lastSeen DESC, email ASC\n `,\n )\n .all(minMessages, minUnreadRate, status, status) as NewsletterRow[];\n\n return rows.map(mapNewsletterRow);\n}\n\nexport async function updateNewsletterStatus(\n email: string,\n status: NewsletterStatus,\n): Promise<void> {\n if (![\"active\", \"unsubscribed\", \"archived\"].includes(status)) {\n throw new Error(`Invalid newsletter status: ${status}`);\n }\n\n const sqlite = getStatsSqlite();\n const result = sqlite\n .prepare(\n `\n UPDATE newsletter_senders\n SET status = ?\n WHERE LOWER(email) = LOWER(?)\n `,\n )\n .run(status, email.trim());\n\n if (result.changes === 0) {\n throw new Error(`Newsletter sender not found: ${email}`);\n }\n}\n","import type Database from \"better-sqlite3\";\nimport {\n clampPercentage,\n extractDomain,\n getPeriodStart,\n getStatsSqlite,\n normalizeLimit,\n resolveLabelName,\n roundPercent,\n type StatsPeriod,\n} from \"./common.js\";\n\nexport interface SenderOptions {\n limit?: number;\n period?: StatsPeriod;\n minMessages?: number;\n minUnreadRate?: number;\n}\n\nexport interface SenderStat {\n email: string;\n name: string;\n totalMessages: number;\n unreadMessages: number;\n unreadRate: number;\n lastEmailDate: number;\n firstEmailDate: number;\n labels: string[];\n}\n\nexport interface SenderRecentEmail {\n id: string;\n fromAddress: string;\n subject: string;\n date: number;\n isRead: boolean;\n}\n\nexport interface SenderDetail extends SenderStat {\n type: \"sender\" | \"domain\";\n query: string;\n matchingSenders: string[];\n recentEmails: SenderRecentEmail[];\n}\n\ninterface AggregateRow {\n email: string;\n name: string | null;\n totalMessages: number;\n unreadMessages: number;\n lastEmailDate: number;\n firstEmailDate: number;\n}\n\ninterface RecentEmailRow {\n id: string;\n fromAddress: string;\n subject: string;\n date: number;\n isRead: number;\n}\n\nfunction buildSenderWhereClause(period?: StatsPeriod): {\n clause: string;\n params: Array<number | string>;\n} {\n const whereParts = [\n \"from_address IS NOT NULL\",\n \"TRIM(from_address) <> ''\",\n ];\n const params: Array<number | string> = [];\n const periodStart = getPeriodStart(period);\n\n if (periodStart !== null) {\n whereParts.push(\"date >= ?\");\n params.push(periodStart);\n }\n\n return {\n clause: whereParts.join(\" AND \"),\n params,\n };\n}\n\nfunction mapAggregateRow(\n sqlite: Database.Database,\n row: AggregateRow,\n whereClause: string,\n params: Array<number | string>,\n): SenderStat {\n return {\n email: row.email,\n name: row.name?.trim() || row.email,\n totalMessages: row.totalMessages,\n unreadMessages: row.unreadMessages,\n unreadRate: roundPercent(row.unreadMessages, row.totalMessages),\n lastEmailDate: row.lastEmailDate,\n firstEmailDate: row.firstEmailDate,\n labels: getTopLabels(sqlite, whereClause, params),\n };\n}\n\nfunction getTopLabels(\n sqlite: Database.Database,\n whereClause: string,\n params: Array<number | string>,\n): string[] {\n const rows = sqlite\n .prepare(\n `\n SELECT label.value AS labelId, COUNT(*) AS totalMessages\n FROM emails AS e, json_each(e.label_ids) AS label\n WHERE ${whereClause}\n GROUP BY label.value\n ORDER BY totalMessages DESC, label.value ASC\n LIMIT 5\n `,\n )\n .all(...params) as Array<{ labelId: string }>;\n\n return rows.map((row) => resolveLabelName(row.labelId));\n}\n\nfunction getRecentEmailsForMatch(\n sqlite: Database.Database,\n whereClause: string,\n params: Array<number | string>,\n): SenderRecentEmail[] {\n const rows = sqlite\n .prepare(\n `\n SELECT\n id,\n from_address AS fromAddress,\n subject,\n date,\n is_read AS isRead\n FROM emails\n WHERE ${whereClause}\n ORDER BY date DESC\n LIMIT 10\n `,\n )\n .all(...params) as RecentEmailRow[];\n\n return rows.map((row) => ({\n id: row.id,\n fromAddress: row.fromAddress,\n subject: row.subject,\n date: row.date,\n isRead: row.isRead === 1,\n }));\n}\n\nfunction getMatchingSenders(\n sqlite: Database.Database,\n whereClause: string,\n params: Array<number | string>,\n): string[] {\n const rows = sqlite\n .prepare(\n `\n SELECT from_address AS email, COUNT(*) AS totalMessages, MAX(date) AS lastEmailDate\n FROM emails\n WHERE ${whereClause}\n GROUP BY from_address\n ORDER BY totalMessages DESC, lastEmailDate DESC, email ASC\n `,\n )\n .all(...params) as Array<{ email: string }>;\n\n return rows.map((row) => row.email);\n}\n\nexport async function getTopSenders(options: SenderOptions = {}): Promise<SenderStat[]> {\n const sqlite = getStatsSqlite();\n const limit = normalizeLimit(options.limit, 20);\n const minMessages = normalizeLimit(options.minMessages, 1);\n const minUnreadRate = clampPercentage(options.minUnreadRate, 0);\n const { clause, params } = buildSenderWhereClause(options.period);\n\n const rows = sqlite\n .prepare(\n `\n SELECT\n from_address AS email,\n COALESCE(MAX(NULLIF(TRIM(from_name), '')), from_address) AS name,\n COUNT(*) AS totalMessages,\n SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) AS unreadMessages,\n MAX(date) AS lastEmailDate,\n MIN(date) AS firstEmailDate\n FROM emails\n WHERE ${clause}\n GROUP BY from_address\n HAVING COUNT(*) >= ?\n AND (100.0 * SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) / COUNT(*)) >= ?\n ORDER BY totalMessages DESC, lastEmailDate DESC, email ASC\n LIMIT ?\n `,\n )\n .all(...params, minMessages, minUnreadRate, limit) as AggregateRow[];\n\n return rows.map((row) =>\n mapAggregateRow(\n sqlite,\n row,\n `from_address = ?${clause.includes(\"date >= ?\") ? \" AND date >= ?\" : \"\"}`,\n clause.includes(\"date >= ?\") ? [row.email, ...params] : [row.email],\n ),\n );\n}\n\nexport async function getSenderStats(emailOrDomain: string): Promise<SenderDetail | null> {\n const sqlite = getStatsSqlite();\n const query = emailOrDomain.trim().toLowerCase();\n\n if (!query) {\n return null;\n }\n\n const isDomain = query.startsWith(\"@\");\n const domain = isDomain ? query.slice(1) : \"\";\n\n if (isDomain && !domain) {\n return null;\n }\n\n const whereClause = isDomain\n ? \"from_address IS NOT NULL AND INSTR(from_address, '@') > 0 AND LOWER(SUBSTR(from_address, INSTR(from_address, '@') + 1)) = ?\"\n : \"LOWER(from_address) = ?\";\n const params = [isDomain ? domain : query];\n\n const row = sqlite\n .prepare(\n `\n SELECT\n ${isDomain ? \"? AS email\" : \"LOWER(from_address) AS email\"},\n ${\n isDomain\n ? \"? AS name\"\n : \"COALESCE(MAX(NULLIF(TRIM(from_name), '')), LOWER(from_address)) AS name\"\n },\n COUNT(*) AS totalMessages,\n SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) AS unreadMessages,\n MAX(date) AS lastEmailDate,\n MIN(date) AS firstEmailDate\n FROM emails\n WHERE ${whereClause}\n `,\n )\n .get(\n ...(isDomain ? [`@${domain}`, domain] : []),\n ...params,\n ) as AggregateRow | undefined;\n\n if (!row || row.totalMessages === 0) {\n return null;\n }\n\n const displayQuery = isDomain ? `@${domain}` : query;\n const detail = mapAggregateRow(\n sqlite,\n row,\n whereClause,\n params,\n );\n\n return {\n ...detail,\n type: isDomain ? \"domain\" : \"sender\",\n query: displayQuery,\n matchingSenders: getMatchingSenders(sqlite, whereClause, params),\n recentEmails: getRecentEmailsForMatch(sqlite, whereClause, params),\n };\n}\n\nexport async function getSenderDomains(options: SenderOptions = {}): Promise<SenderStat[]> {\n const sqlite = getStatsSqlite();\n const limit = normalizeLimit(options.limit, 20);\n const minMessages = normalizeLimit(options.minMessages, 1);\n const minUnreadRate = clampPercentage(options.minUnreadRate, 0);\n const { clause, params } = buildSenderWhereClause(options.period);\n\n const rows = sqlite\n .prepare(\n `\n SELECT\n LOWER(SUBSTR(from_address, INSTR(from_address, '@') + 1)) AS email,\n LOWER(SUBSTR(from_address, INSTR(from_address, '@') + 1)) AS name,\n COUNT(*) AS totalMessages,\n SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) AS unreadMessages,\n MAX(date) AS lastEmailDate,\n MIN(date) AS firstEmailDate\n FROM emails\n WHERE ${clause}\n AND INSTR(from_address, '@') > 0\n GROUP BY LOWER(SUBSTR(from_address, INSTR(from_address, '@') + 1))\n HAVING COUNT(*) >= ?\n AND (100.0 * SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) / COUNT(*)) >= ?\n ORDER BY totalMessages DESC, lastEmailDate DESC, email ASC\n LIMIT ?\n `,\n )\n .all(...params, minMessages, minUnreadRate, limit) as AggregateRow[];\n\n return rows\n .filter((row) => extractDomain(row.email) !== null || row.email.includes(\".\"))\n .map((row) => {\n const domain = row.email.toLowerCase();\n const stat = mapAggregateRow(\n sqlite,\n {\n ...row,\n email: `@${domain}`,\n name: domain,\n },\n `from_address IS NOT NULL AND INSTR(from_address, '@') > 0 AND LOWER(SUBSTR(from_address, INSTR(from_address, '@') + 1)) = ?${\n clause.includes(\"date >= ?\") ? \" AND date >= ?\" : \"\"\n }`,\n clause.includes(\"date >= ?\") ? [domain, ...params] : [domain],\n );\n\n return {\n ...stat,\n name: domain,\n };\n });\n}\n","import {\n getStatsSqlite,\n startOfLocalDay,\n startOfLocalMonth,\n startOfLocalWeek,\n} from \"./common.js\";\n\nexport type VolumeGranularity = \"hour\" | \"day\" | \"week\" | \"month\";\n\nexport interface VolumePoint {\n period: string;\n received: number;\n read: number;\n unread: number;\n archived: number;\n}\n\nexport interface InboxOverview {\n total: number;\n unread: number;\n starred: number;\n today: { received: number; unread: number };\n thisWeek: { received: number; unread: number };\n thisMonth: { received: number; unread: number };\n oldestUnread: Date | null;\n}\n\ninterface VolumeRow extends VolumePoint {}\n\ninterface OverviewRow {\n total: number;\n unread: number;\n starred: number;\n todayReceived: number;\n todayUnread: number;\n thisWeekReceived: number;\n thisWeekUnread: number;\n thisMonthReceived: number;\n thisMonthUnread: number;\n oldestUnread: number | null;\n}\n\nfunction getBucketExpression(granularity: VolumeGranularity): string {\n switch (granularity) {\n case \"hour\":\n return \"strftime('%Y-%m-%d %H:00', date / 1000, 'unixepoch', 'localtime')\";\n case \"day\":\n return \"strftime('%Y-%m-%d', date / 1000, 'unixepoch', 'localtime')\";\n case \"week\":\n return \"printf('%s-W%02d', strftime('%Y', date / 1000, 'unixepoch', 'localtime'), CAST(strftime('%W', date / 1000, 'unixepoch', 'localtime') AS INTEGER))\";\n case \"month\":\n return \"strftime('%Y-%m', date / 1000, 'unixepoch', 'localtime')\";\n }\n}\n\nexport async function getVolumeByPeriod(\n granularity: VolumeGranularity,\n range?: { start?: number; end?: number },\n): Promise<VolumePoint[]> {\n const sqlite = getStatsSqlite();\n const whereParts: string[] = [];\n const params: number[] = [];\n\n if (range?.start !== undefined) {\n whereParts.push(\"date >= ?\");\n params.push(range.start);\n }\n\n if (range?.end !== undefined) {\n whereParts.push(\"date <= ?\");\n params.push(range.end);\n }\n\n const whereClause = whereParts.length > 0 ? `WHERE ${whereParts.join(\" AND \")}` : \"\";\n const bucketExpression = getBucketExpression(granularity);\n\n const rows = sqlite\n .prepare(\n `\n SELECT\n ${bucketExpression} AS period,\n COUNT(*) AS received,\n SUM(CASE WHEN is_read = 1 THEN 1 ELSE 0 END) AS read,\n SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) AS unread,\n SUM(\n CASE\n WHEN EXISTS (\n SELECT 1\n FROM json_each(emails.label_ids)\n WHERE json_each.value = 'INBOX'\n ) THEN 0\n ELSE 1\n END\n ) AS archived\n FROM emails\n ${whereClause}\n GROUP BY period\n ORDER BY MIN(date) ASC\n `,\n )\n .all(...params) as VolumeRow[];\n\n return rows.map((row) => ({\n period: row.period,\n received: row.received,\n read: row.read,\n unread: row.unread,\n archived: row.archived,\n }));\n}\n\nexport async function getInboxOverview(): Promise<InboxOverview> {\n const sqlite = getStatsSqlite();\n const now = Date.now();\n const todayStart = startOfLocalDay(now);\n const weekStart = startOfLocalWeek(now);\n const monthStart = startOfLocalMonth(now);\n\n const row = sqlite\n .prepare(\n `\n SELECT\n COUNT(*) AS total,\n SUM(CASE WHEN is_read = 0 THEN 1 ELSE 0 END) AS unread,\n SUM(CASE WHEN is_starred = 1 THEN 1 ELSE 0 END) AS starred,\n SUM(CASE WHEN date >= ? THEN 1 ELSE 0 END) AS todayReceived,\n SUM(CASE WHEN date >= ? AND is_read = 0 THEN 1 ELSE 0 END) AS todayUnread,\n SUM(CASE WHEN date >= ? THEN 1 ELSE 0 END) AS thisWeekReceived,\n SUM(CASE WHEN date >= ? AND is_read = 0 THEN 1 ELSE 0 END) AS thisWeekUnread,\n SUM(CASE WHEN date >= ? THEN 1 ELSE 0 END) AS thisMonthReceived,\n SUM(CASE WHEN date >= ? AND is_read = 0 THEN 1 ELSE 0 END) AS thisMonthUnread,\n MIN(CASE WHEN is_read = 0 THEN date ELSE NULL END) AS oldestUnread\n FROM emails\n `,\n )\n .get(\n todayStart,\n todayStart,\n weekStart,\n weekStart,\n monthStart,\n monthStart,\n ) as OverviewRow | undefined;\n\n return {\n total: row?.total || 0,\n unread: row?.unread || 0,\n starred: row?.starred || 0,\n today: {\n received: row?.todayReceived || 0,\n unread: row?.todayUnread || 0,\n },\n thisWeek: {\n received: row?.thisWeekReceived || 0,\n unread: row?.thisWeekUnread || 0,\n },\n thisMonth: {\n received: row?.thisMonthReceived || 0,\n unread: row?.thisMonthUnread || 0,\n },\n oldestUnread: row?.oldestUnread ? new Date(row.oldestUnread) : null,\n };\n}\n","import { getRun, getRunItems, getRecentRuns, getRunsByRule } from \"../actions/audit.js\";\n\nexport async function getExecutionHistory(ruleId?: string, limit: number = 20) {\n const runs = ruleId ? await getRunsByRule(ruleId) : await getRecentRuns(limit);\n return runs.slice(0, limit);\n}\n\nexport async function getExecutionRun(runId: string) {\n const run = await getRun(runId);\n\n if (!run) {\n return null;\n }\n\n return {\n run,\n items: await getRunItems(runId),\n };\n}\n\nexport async function getExecutionRunItems(runId: string) {\n return getRunItems(runId);\n}\n\nexport async function getExecutionStats(ruleId?: string) {\n const runs = ruleId ? await getRunsByRule(ruleId) : await getRecentRuns(10_000);\n\n return {\n totalRuns: runs.length,\n plannedRuns: runs.filter((run) => run.status === \"planned\").length,\n appliedRuns: runs.filter((run) => run.status === \"applied\").length,\n partialRuns: runs.filter((run) => run.status === \"partial\").length,\n errorRuns: runs.filter((run) => run.status === \"error\").length,\n undoneRuns: runs.filter((run) => run.status === \"undone\").length,\n lastExecutionAt: runs[0]?.createdAt ?? null,\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport type { Action, Conditions, Rule } from \"./types.js\";\nimport { loadAllRules } from \"./loader.js\";\n\nexport interface DeployedRuleRecord {\n id: string;\n name: string;\n description: string;\n enabled: boolean;\n yamlHash: string | null;\n conditions: Conditions;\n actions: Action[];\n priority: number;\n deployedAt: number | null;\n createdAt: number | null;\n}\n\nexport type DeployStatus = \"created\" | \"updated\" | \"unchanged\";\n\nexport interface DeployResult extends DeployedRuleRecord {\n status: DeployStatus;\n}\n\nexport interface RuleExecutionStats {\n totalRuns: number;\n plannedRuns: number;\n appliedRuns: number;\n partialRuns: number;\n errorRuns: number;\n undoneRuns: number;\n lastExecutionAt: number | null;\n lastExecutionStatus: string | null;\n lastRunId: string | null;\n}\n\nexport interface RuleStatus extends DeployedRuleRecord, RuleExecutionStats {}\n\nexport interface DriftEntry {\n name: string;\n filePath?: string;\n fileHash?: string | null;\n deployedHash?: string | null;\n status: \"in_sync\" | \"changed\" | \"missing_file\" | \"not_deployed\";\n}\n\nexport interface DriftReport {\n drifted: boolean;\n entries: DriftEntry[];\n}\n\nfunction getDatabase() {\n const config = loadConfig();\n return getSqlite(config.dbPath);\n}\n\nfunction parseJson<T>(value: string | null | undefined, fallback: T): T {\n if (!value) {\n return fallback;\n }\n\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction rowToRule(row: {\n id: string;\n name: string;\n description: string | null;\n enabled: number | null;\n yamlHash: string | null;\n conditions: string;\n actions: string;\n priority: number | null;\n deployedAt: number | null;\n createdAt: number | null;\n}): DeployedRuleRecord {\n return {\n id: row.id,\n name: row.name,\n description: row.description ?? \"\",\n enabled: row.enabled !== 0,\n yamlHash: row.yamlHash,\n conditions: parseJson<Conditions>(row.conditions, { operator: \"OR\", matchers: [] }),\n actions: parseJson<Action[]>(row.actions, []),\n priority: row.priority ?? 50,\n deployedAt: row.deployedAt,\n createdAt: row.createdAt,\n };\n}\n\nfunction ruleSelectSql(whereClause: string = \"\", limitClause: string = \"\"): string {\n return `\n SELECT\n id,\n name,\n description,\n enabled,\n yaml_hash AS yamlHash,\n conditions,\n actions,\n priority,\n deployed_at AS deployedAt,\n created_at AS createdAt\n FROM rules\n ${whereClause}\n ORDER BY COALESCE(priority, 50) ASC, name ASC\n ${limitClause}\n `;\n}\n\nasync function loadRuleRows(): Promise<DeployedRuleRecord[]> {\n const sqlite = getDatabase();\n const rows = sqlite.prepare(ruleSelectSql()).all() as Parameters<typeof rowToRule>[0][];\n return rows.map(rowToRule);\n}\n\nexport async function getRuleByName(name: string): Promise<DeployedRuleRecord | null> {\n const trimmed = name.trim();\n\n if (!trimmed) {\n return null;\n }\n\n const sqlite = getDatabase();\n const row = sqlite\n .prepare(ruleSelectSql(\"WHERE name = ? OR id = ?\", \"LIMIT 1\"))\n .get(trimmed, trimmed) as Parameters<typeof rowToRule>[0] | undefined;\n\n return row ? rowToRule(row) : null;\n}\n\nexport async function getAllRules(): Promise<DeployedRuleRecord[]> {\n return loadRuleRows();\n}\n\nfunction upsertRule(rule: Rule, yamlHash: string): DeployResult {\n const sqlite = getDatabase();\n const existing = sqlite\n .prepare(ruleSelectSql(\"WHERE name = ?\", \"LIMIT 1\"))\n .get(rule.name) as Parameters<typeof rowToRule>[0] | undefined;\n\n if (existing && existing.yamlHash === yamlHash) {\n return {\n ...rowToRule(existing),\n status: \"unchanged\",\n };\n }\n\n const now = Date.now();\n\n if (existing) {\n sqlite\n .prepare(\n `\n UPDATE rules\n SET description = ?, enabled = ?, yaml_hash = ?, conditions = ?, actions = ?, priority = ?, deployed_at = ?\n WHERE id = ?\n `,\n )\n .run(\n rule.description,\n rule.enabled ? 1 : 0,\n yamlHash,\n serializeJson(rule.conditions),\n serializeJson(rule.actions),\n rule.priority,\n now,\n existing.id,\n );\n } else {\n sqlite\n .prepare(\n `\n INSERT INTO rules (\n id, name, description, enabled, yaml_hash, conditions, actions, priority, deployed_at, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `,\n )\n .run(\n randomUUID(),\n rule.name,\n rule.description,\n rule.enabled ? 1 : 0,\n yamlHash,\n serializeJson(rule.conditions),\n serializeJson(rule.actions),\n rule.priority,\n now,\n now,\n );\n }\n\n const refreshed = sqlite\n .prepare(ruleSelectSql(\"WHERE name = ?\", \"LIMIT 1\"))\n .get(rule.name) as Parameters<typeof rowToRule>[0] | undefined;\n\n if (!refreshed) {\n throw new Error(`Failed to load deployed rule: ${rule.name}`);\n }\n\n return {\n ...rowToRule(refreshed),\n status: existing ? \"updated\" : \"created\",\n };\n}\n\nexport async function deployRule(rule: Rule, yamlHash: string): Promise<DeployResult> {\n return upsertRule(rule, yamlHash);\n}\n\nexport async function deployLoadedRule(loaded: { rule: Rule; yamlHash: string }): Promise<DeployResult> {\n return deployRule(loaded.rule, loaded.yamlHash);\n}\n\nexport async function deployAllRules(rulesDir: string): Promise<DeployResult[]> {\n const loadedRules = await loadAllRules(rulesDir);\n const deployed: DeployResult[] = [];\n\n for (const entry of loadedRules) {\n deployed.push(await deployRule(entry.rule, entry.yamlHash));\n }\n\n return deployed;\n}\n\nexport async function undeployRule(name: string): Promise<boolean> {\n const sqlite = getDatabase();\n const result = sqlite.prepare(`DELETE FROM rules WHERE name = ? OR id = ?`).run(name, name);\n return result.changes > 0;\n}\n\nasync function getExecutionStatsByRuleId(ruleId: string): Promise<RuleExecutionStats> {\n const sqlite = getDatabase();\n const counts = sqlite\n .prepare(\n `\n SELECT\n COUNT(*) AS totalRuns,\n COALESCE(SUM(CASE WHEN status = 'planned' THEN 1 ELSE 0 END), 0) AS plannedRuns,\n COALESCE(SUM(CASE WHEN status = 'applied' THEN 1 ELSE 0 END), 0) AS appliedRuns,\n COALESCE(SUM(CASE WHEN status = 'partial' THEN 1 ELSE 0 END), 0) AS partialRuns,\n COALESCE(SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END), 0) AS errorRuns,\n COALESCE(SUM(CASE WHEN status = 'undone' THEN 1 ELSE 0 END), 0) AS undoneRuns,\n MAX(created_at) AS lastExecutionAt\n FROM execution_runs\n WHERE rule_id = ?\n `,\n )\n .get(ruleId) as\n | {\n totalRuns: number;\n plannedRuns: number;\n appliedRuns: number;\n partialRuns: number;\n errorRuns: number;\n undoneRuns: number;\n lastExecutionAt: number | null;\n }\n | undefined;\n\n const lastRun = sqlite\n .prepare(\n `\n SELECT id, status, created_at AS createdAt\n FROM execution_runs\n WHERE rule_id = ?\n ORDER BY COALESCE(created_at, 0) DESC, id DESC\n LIMIT 1\n `,\n )\n .get(ruleId) as { id: string; status: string; createdAt: number | null } | undefined;\n\n return {\n totalRuns: counts?.totalRuns ?? 0,\n plannedRuns: counts?.plannedRuns ?? 0,\n appliedRuns: counts?.appliedRuns ?? 0,\n partialRuns: counts?.partialRuns ?? 0,\n errorRuns: counts?.errorRuns ?? 0,\n undoneRuns: counts?.undoneRuns ?? 0,\n lastExecutionAt: counts?.lastExecutionAt ?? null,\n lastExecutionStatus: lastRun?.status ?? null,\n lastRunId: lastRun?.id ?? null,\n };\n}\n\nexport async function getRuleStatus(name: string): Promise<RuleStatus | null> {\n const rule = await getRuleByName(name);\n\n if (!rule) {\n return null;\n }\n\n const stats = await getExecutionStatsByRuleId(rule.id);\n return {\n ...rule,\n ...stats,\n };\n}\n\nexport async function getAllRulesStatus(): Promise<RuleStatus[]> {\n const rules = await loadRuleRows();\n const statuses = await Promise.all(\n rules.map(async (rule) => ({\n ...rule,\n ...(await getExecutionStatsByRuleId(rule.id)),\n })),\n );\n\n return statuses;\n}\n\nexport async function detectDrift(rulesDir: string): Promise<DriftReport> {\n const loadedRules = await loadAllRules(rulesDir);\n const deployedRules = await loadRuleRows();\n const deployedByName = new Map(deployedRules.map((rule) => [rule.name, rule]));\n const fileByName = new Map(loadedRules.map((entry) => [entry.rule.name, entry]));\n const entries: DriftEntry[] = [];\n\n for (const entry of loadedRules) {\n const deployed = deployedByName.get(entry.rule.name);\n\n if (!deployed) {\n entries.push({\n name: entry.rule.name,\n filePath: entry.path,\n fileHash: entry.yamlHash,\n deployedHash: null,\n status: \"not_deployed\",\n });\n continue;\n }\n\n entries.push({\n name: entry.rule.name,\n filePath: entry.path,\n fileHash: entry.yamlHash,\n deployedHash: deployed.yamlHash,\n status: deployed.yamlHash === entry.yamlHash ? \"in_sync\" : \"changed\",\n });\n }\n\n for (const deployed of deployedRules) {\n if (fileByName.has(deployed.name)) {\n continue;\n }\n\n entries.push({\n name: deployed.name,\n deployedHash: deployed.yamlHash,\n status: \"missing_file\",\n });\n }\n\n return {\n drifted: entries.some((entry) => entry.status !== \"in_sync\"),\n entries,\n };\n}\n\nasync function setRuleEnabled(name: string, enabled: boolean): Promise<DeployedRuleRecord> {\n const rule = await getRuleByName(name);\n\n if (!rule) {\n throw new Error(`Rule not found: ${name}`);\n }\n\n const sqlite = getDatabase();\n sqlite\n .prepare(\n `\n UPDATE rules\n SET enabled = ?\n WHERE id = ?\n `,\n )\n .run(enabled ? 1 : 0, rule.id);\n\n const refreshed = await getRuleByName(rule.id);\n\n if (!refreshed) {\n throw new Error(`Failed to refresh rule after update: ${name}`);\n }\n\n return refreshed;\n}\n\nexport async function enableRule(name: string): Promise<DeployedRuleRecord> {\n return setRuleEnabled(name, true);\n}\n\nexport async function disableRule(name: string): Promise<DeployedRuleRecord> {\n return setRuleEnabled(name, false);\n}\n","import { createHash } from \"node:crypto\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport YAML from \"yaml\";\nimport { RuleSchema, type Rule } from \"./types.js\";\n\nexport interface LoadedRuleFile {\n name: string;\n description: string;\n enabled: boolean;\n priority: number;\n conditions: Rule[\"conditions\"];\n actions: Rule[\"actions\"];\n path: string;\n yaml: string;\n yamlHash: string;\n rule: Rule;\n}\n\nfunction isRuleFile(filename: string): boolean {\n const lower = filename.toLowerCase();\n return lower.endsWith(\".yaml\") || lower.endsWith(\".yml\");\n}\n\nfunction formatZodError(path: string, error: Error): string {\n return `${path}: ${error.message}`;\n}\n\nfunction formatYamlErrors(path: string, errors: unknown[]): Error {\n const messages = errors.map((error) => {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n });\n\n return new Error(`${path}: invalid YAML - ${messages.join(\"; \")}`);\n}\n\nexport function hashRule(yamlContent: string): string {\n return createHash(\"sha256\").update(yamlContent, \"utf8\").digest(\"hex\");\n}\n\nexport function parseRuleYaml(yamlContent: string, path: string = \"<rule>\"): Rule {\n const document = YAML.parseDocument(yamlContent, {\n prettyErrors: true,\n });\n\n if (document.errors.length > 0) {\n throw formatYamlErrors(path, document.errors);\n }\n\n const parsed = document.toJS({\n mapAsMap: false,\n maxAliasCount: 50,\n });\n\n const result = RuleSchema.safeParse(parsed);\n\n if (!result.success) {\n const message = result.error.issues\n .map((issue) => {\n const issuePath = issue.path.length > 0 ? issue.path.join(\".\") : \"root\";\n return `${issuePath}: ${issue.message}`;\n })\n .join(\"; \");\n\n throw new Error(formatZodError(path, new Error(message)));\n }\n\n return result.data;\n}\n\nexport async function loadRuleFile(path: string): Promise<LoadedRuleFile> {\n const yaml = await readFile(path, \"utf8\");\n const rule = parseRuleYaml(yaml, path);\n\n return {\n ...rule,\n path,\n yaml,\n yamlHash: hashRule(yaml),\n rule,\n };\n}\n\nexport async function loadAllRules(rulesDir: string): Promise<LoadedRuleFile[]> {\n const entries = await readdir(rulesDir, { withFileTypes: true });\n const filePaths = entries\n .filter((entry) => entry.isFile() && isRuleFile(entry.name))\n .map((entry) => join(rulesDir, entry.name))\n .sort((left, right) => left.localeCompare(right));\n\n const loaded = await Promise.all(filePaths.map(async (path) => loadRuleFile(path)));\n return loaded;\n}\n","import { z } from \"zod\";\n\nexport const RuleNameSchema = z\n .string()\n .min(1, \"Rule name is required\")\n .regex(\n /^[a-z0-9]+(?:-[a-z0-9]+)*$/,\n \"Rule name must be kebab-case (lowercase letters, numbers, and single hyphens)\",\n );\n\nexport const RuleFieldSchema = z.enum([\"from\", \"to\", \"subject\", \"snippet\", \"labels\"]);\n\nconst RegexStringSchema = z\n .string()\n .min(1, \"Pattern must not be empty\")\n .superRefine((value, ctx) => {\n try {\n new RegExp(value);\n } catch (error) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid regular expression: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n });\n\nexport const MatcherSchema = z\n .object({\n // `snippet` is the only cached free-text matcher in MVP.\n field: RuleFieldSchema,\n pattern: RegexStringSchema.optional(),\n contains: z.array(z.string().min(1)).min(1).optional(),\n values: z.array(z.string().min(1)).min(1).optional(),\n exclude: z.boolean().default(false),\n })\n .strict()\n .superRefine((value, ctx) => {\n if (!value.pattern && !value.contains && !value.values) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"Matcher must provide at least one of pattern, contains, or values\",\n path: [\"pattern\"],\n });\n }\n });\n\nexport const ConditionsSchema = z\n .object({\n operator: z.enum([\"AND\", \"OR\"]),\n matchers: z.array(MatcherSchema).min(1, \"At least one matcher is required\"),\n })\n .strict();\n\nconst LabelActionSchema = z.object({\n type: z.literal(\"label\"),\n label: z.string().min(1, \"Label name is required\"),\n});\n\nconst ArchiveActionSchema = z.object({ type: z.literal(\"archive\") });\nconst MarkReadActionSchema = z.object({ type: z.literal(\"mark_read\") });\nconst ForwardActionSchema = z.object({\n type: z.literal(\"forward\"),\n to: z.string().email(\"Forward destination must be a valid email address\"),\n});\nconst MarkSpamActionSchema = z.object({ type: z.literal(\"mark_spam\") });\n\nexport const ActionSchema = z\n .discriminatedUnion(\"type\", [\n LabelActionSchema,\n ArchiveActionSchema,\n MarkReadActionSchema,\n ForwardActionSchema,\n MarkSpamActionSchema,\n ]);\n\nexport const RuleSchema = z\n .object({\n name: RuleNameSchema,\n description: z.string(),\n enabled: z.boolean().default(true),\n priority: z.number().int().min(0).default(50),\n conditions: ConditionsSchema,\n actions: z.array(ActionSchema).min(1, \"At least one action is required\"),\n })\n .strict();\n\nexport function validateRule(input: unknown): Rule {\n return RuleSchema.parse(input);\n}\n\nexport type Matcher = z.infer<typeof MatcherSchema>;\nexport type Conditions = z.infer<typeof ConditionsSchema>;\nexport type Action = z.infer<typeof ActionSchema>;\nexport type Rule = z.infer<typeof RuleSchema>;\n","import { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport type { EmailMessage } from \"../gmail/types.js\";\nimport type { Conditions, Matcher, Rule } from \"./types.js\";\nimport { getRuleByName } from \"./deploy.js\";\n\nexport interface MatchedEmail {\n email: EmailMessage;\n matchedFields: string[];\n}\n\ninterface EmailRow {\n id: string;\n thread_id: string | null;\n from_address: string | null;\n from_name: string | null;\n to_addresses: string | null;\n subject: string | null;\n snippet: string | null;\n date: number | null;\n is_read: number | null;\n is_starred: number | null;\n label_ids: string | null;\n size_estimate: number | null;\n has_attachments: number | null;\n list_unsubscribe: string | null;\n}\n\nfunction getDatabase() {\n const config = loadConfig();\n return getSqlite(config.dbPath);\n}\n\nfunction parseJsonArray(value: string | null | undefined): string[] {\n if (!value) {\n return [];\n }\n\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed)\n ? parsed.filter((entry): entry is string => typeof entry === \"string\")\n : [];\n } catch {\n return [];\n }\n}\n\nfunction rowToEmail(row: EmailRow): EmailMessage {\n return {\n id: row.id,\n threadId: row.thread_id ?? \"\",\n fromAddress: row.from_address ?? \"\",\n fromName: row.from_name ?? \"\",\n toAddresses: parseJsonArray(row.to_addresses),\n subject: row.subject ?? \"\",\n snippet: row.snippet ?? \"\",\n date: row.date ?? 0,\n isRead: row.is_read === 1,\n isStarred: row.is_starred === 1,\n labelIds: parseJsonArray(row.label_ids),\n sizeEstimate: row.size_estimate ?? 0,\n hasAttachments: row.has_attachments === 1,\n listUnsubscribe: row.list_unsubscribe,\n };\n}\n\nfunction getFieldValues(email: EmailMessage, matcher: Matcher): string[] {\n switch (matcher.field) {\n case \"from\":\n return [email.fromAddress, email.fromName].filter(Boolean);\n case \"to\":\n return email.toAddresses;\n case \"subject\":\n return [email.subject];\n case \"snippet\":\n return [email.snippet];\n case \"labels\":\n return email.labelIds;\n }\n}\n\nfunction normalize(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction exactMatch(values: string[], candidates: string[]): boolean {\n if (values.length === 0 || candidates.length === 0) {\n return false;\n }\n\n const normalizedCandidates = new Set(candidates.map(normalize));\n return values.some((value) => normalizedCandidates.has(normalize(value)));\n}\n\nfunction containsMatch(values: string[], candidates: string[]): boolean {\n if (values.length === 0 || candidates.length === 0) {\n return false;\n }\n\n const normalizedCandidates = candidates.map(normalize);\n return values.some((value) => {\n const needle = normalize(value);\n return normalizedCandidates.some((candidate) => candidate.includes(needle));\n });\n}\n\nfunction patternMatch(pattern: string | undefined, candidates: string[]): boolean {\n if (!pattern || candidates.length === 0) {\n return false;\n }\n\n const regex = new RegExp(pattern);\n return candidates.some((candidate) => regex.test(candidate));\n}\n\nexport function matchField(email: EmailMessage, matcher: Matcher): boolean {\n const candidates = getFieldValues(email, matcher);\n const matched =\n patternMatch(matcher.pattern, candidates) ||\n containsMatch(matcher.contains ?? [], candidates) ||\n exactMatch(matcher.values ?? [], candidates);\n\n return matcher.exclude ? !matched : matched;\n}\n\nexport function matchEmail(\n email: EmailMessage,\n conditions: Conditions,\n): { matches: boolean; matchedFields: string[] } {\n const matchedFields: string[] = [];\n\n if (conditions.operator === \"AND\") {\n for (const matcher of conditions.matchers) {\n const matched = matchField(email, matcher);\n\n if (!matched) {\n return {\n matches: false,\n matchedFields: [],\n };\n }\n\n matchedFields.push(matcher.field);\n }\n\n return {\n matches: true,\n matchedFields: Array.from(new Set(matchedFields)),\n };\n }\n\n for (const matcher of conditions.matchers) {\n if (matchField(email, matcher)) {\n matchedFields.push(matcher.field);\n }\n }\n\n return {\n matches: matchedFields.length > 0,\n matchedFields: Array.from(new Set(matchedFields)),\n };\n}\n\nexport async function findMatchingEmails(\n ruleOrConditions: string | Pick<Rule, \"conditions\"> | Conditions,\n limit?: number,\n): Promise<MatchedEmail[]> {\n const conditions = typeof ruleOrConditions === \"string\"\n ? (await getRuleByName(ruleOrConditions))?.conditions\n : \"conditions\" in ruleOrConditions\n ? ruleOrConditions.conditions\n : ruleOrConditions;\n\n if (!conditions) {\n throw new Error(`Rule not found: ${ruleOrConditions}`);\n }\n\n const sqlite = getDatabase();\n const rows = sqlite\n .prepare(\n `\n SELECT\n id,\n thread_id,\n from_address,\n from_name,\n to_addresses,\n subject,\n snippet,\n date,\n is_read,\n is_starred,\n label_ids,\n size_estimate,\n has_attachments,\n list_unsubscribe\n FROM emails\n ORDER BY COALESCE(date, 0) DESC, id DESC\n `,\n )\n .all() as EmailRow[];\n\n const matches: MatchedEmail[] = [];\n\n for (const row of rows) {\n const email = rowToEmail(row);\n const result = matchEmail(email, conditions);\n\n if (!result.matches) {\n continue;\n }\n\n matches.push({\n email,\n matchedFields: result.matchedFields,\n });\n\n if (limit !== undefined && matches.length >= limit) {\n break;\n }\n }\n\n return matches;\n}\n","import { loadConfig, type Config } from \"../../config.js\";\nimport {\n addExecutionItems,\n createExecutionRun,\n type ExecutionItemRecord,\n type ExecutionItemStatus,\n type ExecutionRunRecord,\n type ExecutionRunStatus,\n} from \"../actions/audit.js\";\nimport {\n archiveEmails,\n forwardEmail,\n labelEmails,\n markRead,\n markSpam,\n} from \"../gmail/modify.js\";\nimport type { GmailModifyItemResult } from \"../gmail/types.js\";\nimport { listMessages } from \"../gmail/messages.js\";\nimport type { GmailTransport } from \"../gmail/transport.js\";\nimport { getAllRules, getRuleByName, type DeployedRuleRecord } from \"./deploy.js\";\nimport { findMatchingEmails } from \"./matcher.js\";\nimport type { Action } from \"./types.js\";\n\nexport interface RunOptions {\n dryRun?: boolean;\n maxEmails?: number;\n query?: string;\n config?: Config;\n transport?: GmailTransport;\n}\n\nexport interface RuleRunItem {\n emailId: string;\n fromAddress: string;\n subject: string;\n date: number;\n matchedFields: string[];\n status: ExecutionItemStatus;\n appliedActions: Action[];\n beforeLabelIds: string[];\n afterLabelIds: string[];\n errorMessage: string | null;\n}\n\nexport interface RuleRunResult {\n rule: DeployedRuleRecord;\n dryRun: boolean;\n maxEmails: number;\n query: string | null;\n matchedCount: number;\n runId: string;\n run: ExecutionRunRecord;\n status: ExecutionRunStatus;\n items: RuleRunItem[];\n skipped?: boolean;\n}\n\nexport interface RunAllRulesResult {\n dryRun: boolean;\n results: RuleRunResult[];\n}\n\nfunction resolveRunStatus(items: RuleRunItem[], dryRun: boolean): ExecutionRunStatus {\n if (dryRun) {\n return \"planned\";\n }\n\n if (items.length === 0) {\n return \"applied\";\n }\n\n if (items.every((item) => item.status === \"applied\")) {\n return \"applied\";\n }\n\n if (items.some((item) => item.status === \"applied\" || item.status === \"warning\")) {\n return \"partial\";\n }\n\n return \"error\";\n}\n\nasync function getQueryLimitedIds(\n query: string,\n maxEmails: number,\n options: Pick<RunOptions, \"config\" | \"transport\">,\n): Promise<Set<string>> {\n if (options.transport) {\n const response = await options.transport.listMessages({\n query,\n maxResults: maxEmails,\n });\n\n return new Set(\n (response.messages || [])\n .map((message) => message.id)\n .filter((id): id is string => Boolean(id)),\n );\n }\n\n const emails = await listMessages(query, maxEmails);\n return new Set(emails.map((email) => email.id));\n}\n\nasync function loadMatchedItems(\n rule: DeployedRuleRecord,\n options: Required<Pick<RunOptions, \"dryRun\" | \"maxEmails\">> & Pick<RunOptions, \"query\" | \"config\" | \"transport\">,\n): Promise<RuleRunItem[]> {\n const matches = await findMatchingEmails(rule, options.maxEmails);\n const allowedIds = options.query\n ? await getQueryLimitedIds(options.query, Math.max(options.maxEmails, 1), {\n config: options.config,\n transport: options.transport,\n })\n : null;\n\n const filtered = allowedIds\n ? matches.filter((match) => allowedIds.has(match.email.id))\n : matches;\n\n return filtered.slice(0, options.maxEmails).map((match) => ({\n emailId: match.email.id,\n fromAddress: match.email.fromAddress,\n subject: match.email.subject,\n date: match.email.date,\n matchedFields: match.matchedFields,\n status: options.dryRun ? \"planned\" : \"applied\",\n appliedActions: options.dryRun ? [] : [...rule.actions],\n beforeLabelIds: [...match.email.labelIds],\n afterLabelIds: [...match.email.labelIds],\n errorMessage: null,\n }));\n}\n\nasync function executeAction(\n emailId: string,\n action: Action,\n options: Pick<RunOptions, \"config\" | \"transport\">,\n): Promise<GmailModifyItemResult> {\n switch (action.type) {\n case \"archive\":\n return (await archiveEmails([emailId], options)).items[0] as GmailModifyItemResult;\n case \"label\":\n return (await labelEmails([emailId], action.label, options)).items[0] as GmailModifyItemResult;\n case \"mark_read\":\n return (await markRead([emailId], options)).items[0] as GmailModifyItemResult;\n case \"forward\":\n return (await forwardEmail(emailId, action.to, options)).items[0] as GmailModifyItemResult;\n case \"mark_spam\":\n return (await markSpam([emailId], options)).items[0] as GmailModifyItemResult;\n }\n}\n\nasync function applyRuleActions(\n item: RuleRunItem,\n actions: Action[],\n options: Pick<RunOptions, \"config\" | \"transport\">,\n): Promise<RuleRunItem> {\n let current = {\n ...item,\n appliedActions: [] as Action[],\n };\n\n for (const action of actions) {\n try {\n const result = await executeAction(item.emailId, action, options);\n current = {\n ...current,\n status: result.status,\n appliedActions: [...current.appliedActions, ...result.appliedActions],\n afterLabelIds: [...result.afterLabelIds],\n errorMessage: result.errorMessage ?? null,\n };\n\n if (result.status === \"error\") {\n break;\n }\n } catch (error) {\n current = {\n ...current,\n status: \"error\",\n errorMessage: error instanceof Error ? error.message : String(error),\n };\n break;\n }\n }\n\n return current;\n}\n\nasync function recordRuleRun(\n rule: DeployedRuleRecord,\n options: Required<Pick<RunOptions, \"dryRun\" | \"maxEmails\">> & Pick<RunOptions, \"query\">,\n items: RuleRunItem[],\n): Promise<{ runId: string; run: ExecutionRunRecord; status: ExecutionRunStatus }> {\n const status = resolveRunStatus(items, options.dryRun);\n const run = await createExecutionRun({\n sourceType: \"rule\",\n ruleId: rule.id,\n dryRun: options.dryRun,\n requestedActions: rule.actions,\n query: options.query ?? null,\n status,\n });\n\n await addExecutionItems(\n run.id,\n items.map((item) => ({\n emailId: item.emailId,\n status: item.status,\n appliedActions: item.appliedActions,\n beforeLabelIds: item.beforeLabelIds,\n afterLabelIds: item.afterLabelIds,\n errorMessage: item.errorMessage,\n })),\n );\n\n return {\n runId: run.id,\n run,\n status,\n };\n}\n\nexport async function runRule(name: string, options: RunOptions): Promise<RuleRunResult> {\n const dryRun = options.dryRun ?? true;\n const maxEmails = options.maxEmails ?? 100;\n const config = options.config ?? loadConfig();\n const rule = await getRuleByName(name);\n\n if (!rule) {\n throw new Error(`Rule not found: ${name}`);\n }\n\n if (!rule.enabled) {\n const run = await createExecutionRun({\n sourceType: \"rule\",\n ruleId: rule.id,\n dryRun,\n requestedActions: rule.actions,\n query: options.query ?? null,\n status: \"planned\",\n });\n\n return {\n rule,\n dryRun,\n maxEmails,\n query: options.query ?? null,\n matchedCount: 0,\n runId: run.id,\n run,\n status: \"planned\",\n items: [],\n skipped: true,\n };\n }\n\n const plannedItems = await loadMatchedItems(rule, {\n dryRun,\n maxEmails,\n query: options.query,\n config,\n transport: options.transport,\n });\n\n const items = dryRun\n ? plannedItems\n : await Promise.all(\n plannedItems.map((item) =>\n applyRuleActions(item, rule.actions, {\n config,\n transport: options.transport,\n }),\n ),\n );\n\n const recorded = await recordRuleRun(\n rule,\n {\n dryRun,\n maxEmails,\n query: options.query,\n },\n items,\n );\n\n return {\n rule,\n dryRun,\n maxEmails,\n query: options.query ?? null,\n matchedCount: items.length,\n runId: recorded.runId,\n run: recorded.run,\n status: recorded.status,\n items,\n };\n}\n\nexport async function runAllRules(options: RunOptions): Promise<RunAllRulesResult> {\n const rules = (await getAllRules())\n .filter((rule) => rule.enabled)\n .sort((left, right) => left.priority - right.priority || left.name.localeCompare(right.name));\n\n const results: RuleRunResult[] = [];\n\n for (const rule of rules) {\n results.push(await runRule(rule.name, options));\n }\n\n return {\n dryRun: options.dryRun ?? true,\n results,\n };\n}\n","import type { Config } from \"../../config.js\";\nimport { loadConfig } from \"../../config.js\";\nimport { createLabel, getLabelId, syncLabels } from \"./labels.js\";\nimport type { GmailTransport } from \"./transport.js\";\nimport { getGmailTransport } from \"./transport.js\";\nimport type {\n GmailFilter,\n GmailFilterActions,\n GmailFilterCriteria,\n GmailLabel,\n RawGmailFilter,\n RawGmailFilterAction,\n RawGmailFilterCriteria,\n} from \"./types.js\";\n\ninterface FilterContext {\n config: Config;\n transport: GmailTransport;\n}\n\ninterface FilterOptions {\n config?: Config;\n transport?: GmailTransport;\n}\n\nexport interface CreateFilterInput {\n // Criteria — at least one required\n from?: string;\n to?: string;\n subject?: string;\n query?: string;\n negatedQuery?: string;\n hasAttachment?: boolean;\n excludeChats?: boolean;\n size?: number;\n sizeComparison?: \"larger\" | \"smaller\";\n // Actions — at least one required\n labelName?: string; // resolved to label ID, auto-created if missing\n archive?: boolean; // -> removeLabelIds: [\"INBOX\"]\n markRead?: boolean; // -> removeLabelIds: [\"UNREAD\"]\n star?: boolean; // -> addLabelIds: [\"STARRED\"]\n forward?: string;\n}\n\nasync function resolveContext(options?: FilterOptions): Promise<FilterContext> {\n const config = options?.config ?? loadConfig();\n const transport = options?.transport ?? (await getGmailTransport(config));\n return { config, transport };\n}\n\nfunction toFilterCriteria(raw: RawGmailFilterCriteria | null | undefined): GmailFilterCriteria {\n return {\n from: raw?.from ?? null,\n to: raw?.to ?? null,\n subject: raw?.subject ?? null,\n query: raw?.query ?? null,\n negatedQuery: raw?.negatedQuery ?? null,\n hasAttachment: raw?.hasAttachment ?? false,\n excludeChats: raw?.excludeChats ?? false,\n size: raw?.size ?? null,\n sizeComparison:\n raw?.sizeComparison === \"larger\" || raw?.sizeComparison === \"smaller\"\n ? raw.sizeComparison\n : null,\n };\n}\n\nfunction toFilterActions(\n raw: RawGmailFilterAction | null | undefined,\n labelMap: Map<string, GmailLabel>,\n): GmailFilterActions {\n const addIds = raw?.addLabelIds ?? [];\n const removeIds = raw?.removeLabelIds ?? [];\n\n const addLabelNames = addIds\n .filter((id) => id !== \"STARRED\")\n .map((id) => labelMap.get(id)?.name ?? id);\n\n const removeLabelNames = removeIds\n .filter((id) => id !== \"INBOX\" && id !== \"UNREAD\")\n .map((id) => labelMap.get(id)?.name ?? id);\n\n return {\n addLabelNames,\n removeLabelNames,\n forward: raw?.forward ?? null,\n archive: removeIds.includes(\"INBOX\"),\n markRead: removeIds.includes(\"UNREAD\"),\n star: addIds.includes(\"STARRED\"),\n };\n}\n\nfunction toGmailFilter(raw: RawGmailFilter, labelMap: Map<string, GmailLabel>): GmailFilter | null {\n const id = raw.id?.trim();\n if (!id) return null;\n\n return {\n id,\n criteria: toFilterCriteria(raw.criteria),\n actions: toFilterActions(raw.action, labelMap),\n };\n}\n\nasync function buildLabelMap(context: FilterContext): Promise<Map<string, GmailLabel>> {\n const labels = await syncLabels({ config: context.config, transport: context.transport });\n const map = new Map<string, GmailLabel>();\n for (const label of labels) {\n map.set(label.id, label);\n }\n return map;\n}\n\nexport async function listFilters(options?: FilterOptions): Promise<GmailFilter[]> {\n const context = await resolveContext(options);\n const [response, labelMap] = await Promise.all([\n context.transport.listFilters(),\n buildLabelMap(context),\n ]);\n\n const raw = response.filter ?? [];\n return raw\n .map((f) => toGmailFilter(f, labelMap))\n .filter((f): f is GmailFilter => f !== null);\n}\n\nexport async function getFilter(id: string, options?: FilterOptions): Promise<GmailFilter> {\n const context = await resolveContext(options);\n const [raw, labelMap] = await Promise.all([\n context.transport.getFilter(id),\n buildLabelMap(context),\n ]);\n\n const filter = toGmailFilter(raw, labelMap);\n if (!filter) {\n throw new Error(`Filter ${id} returned an invalid response from Gmail`);\n }\n return filter;\n}\n\nexport async function createFilter(\n input: CreateFilterInput,\n options?: FilterOptions,\n): Promise<GmailFilter> {\n // Validate at least one criteria field\n const hasCriteria =\n input.from != null ||\n input.to != null ||\n input.subject != null ||\n input.query != null ||\n input.negatedQuery != null ||\n input.hasAttachment != null ||\n input.excludeChats != null ||\n input.size != null;\n\n if (!hasCriteria) {\n throw new Error(\n \"At least one criteria field is required (from, to, subject, query, negatedQuery, hasAttachment, excludeChats, or size)\",\n );\n }\n\n // Validate at least one action field\n const hasAction =\n input.labelName != null ||\n input.archive === true ||\n input.markRead === true ||\n input.star === true ||\n input.forward != null;\n\n if (!hasAction) {\n throw new Error(\n \"At least one action is required (labelName, archive, markRead, star, or forward)\",\n );\n }\n\n const context = await resolveContext(options);\n\n // Build addLabelIds\n const addLabelIds: string[] = [];\n\n if (input.star) {\n addLabelIds.push(\"STARRED\");\n }\n\n if (input.labelName) {\n let labelId = await getLabelId(input.labelName, context);\n if (!labelId) {\n const created = await createLabel(input.labelName, undefined, context);\n labelId = created.id;\n }\n addLabelIds.push(labelId);\n }\n\n // Build removeLabelIds\n const removeLabelIds: string[] = [];\n if (input.archive) removeLabelIds.push(\"INBOX\");\n if (input.markRead) removeLabelIds.push(\"UNREAD\");\n\n const criteria: RawGmailFilterCriteria = {};\n if (input.from) criteria.from = input.from;\n if (input.to) criteria.to = input.to;\n if (input.subject) criteria.subject = input.subject;\n if (input.query) criteria.query = input.query;\n if (input.negatedQuery) criteria.negatedQuery = input.negatedQuery;\n if (input.hasAttachment != null) criteria.hasAttachment = input.hasAttachment;\n if (input.excludeChats != null) criteria.excludeChats = input.excludeChats;\n if (input.size != null) criteria.size = input.size;\n if (input.sizeComparison) criteria.sizeComparison = input.sizeComparison;\n\n const action: RawGmailFilterAction = {};\n if (addLabelIds.length > 0) action.addLabelIds = addLabelIds;\n if (removeLabelIds.length > 0) action.removeLabelIds = removeLabelIds;\n if (input.forward) action.forward = input.forward;\n\n const raw = await context.transport.createFilter({ criteria, action });\n const labelMap = await buildLabelMap(context);\n const filter = toGmailFilter(raw, labelMap);\n\n if (!filter) {\n throw new Error(\"Gmail did not return a valid filter after creation\");\n }\n return filter;\n}\n\nexport async function deleteFilter(id: string, options?: FilterOptions): Promise<void> {\n const context = await resolveContext(options);\n await context.transport.deleteFilter(id);\n}\n","import { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport type { EmailMessage } from \"../gmail/types.js\";\n\ntype EmailRow = {\n id: string;\n thread_id: string;\n from_address: string;\n from_name: string;\n to_addresses: string;\n subject: string;\n snippet: string;\n date: number;\n is_read: number;\n is_starred: number;\n label_ids: string;\n size_estimate: number;\n has_attachments: number;\n list_unsubscribe: string | null;\n};\n\nfunction mapRow(row: EmailRow): EmailMessage {\n return {\n id: row.id,\n threadId: row.thread_id,\n fromAddress: row.from_address,\n fromName: row.from_name,\n toAddresses: JSON.parse(row.to_addresses || \"[]\") as string[],\n subject: row.subject,\n snippet: row.snippet,\n date: row.date,\n isRead: row.is_read === 1,\n isStarred: row.is_starred === 1,\n labelIds: JSON.parse(row.label_ids || \"[]\") as string[],\n sizeEstimate: row.size_estimate,\n hasAttachments: row.has_attachments === 1,\n listUnsubscribe: row.list_unsubscribe,\n };\n}\n\nexport async function getRecentEmails(\n limit: number = 20,\n offset: number = 0,\n): Promise<EmailMessage[]> {\n const config = loadConfig();\n const sqlite = getSqlite(config.dbPath);\n const rows = sqlite\n .prepare(\n `\n SELECT id, thread_id, from_address, from_name, to_addresses, subject, snippet, date,\n is_read, is_starred, label_ids, size_estimate, has_attachments, list_unsubscribe\n FROM emails\n ORDER BY date DESC\n LIMIT ? OFFSET ?\n `,\n )\n .all(limit, offset) as EmailRow[];\n\n return rows.map(mapRow);\n}\n\nexport async function searchLocalEmails(query: string): Promise<EmailMessage[]> {\n const config = loadConfig();\n const sqlite = getSqlite(config.dbPath);\n const pattern = `%${query}%`;\n const rows = sqlite\n .prepare(\n `\n SELECT id, thread_id, from_address, from_name, to_addresses, subject, snippet, date,\n is_read, is_starred, label_ids, size_estimate, has_attachments, list_unsubscribe\n FROM emails\n WHERE subject LIKE ?\n OR from_address LIKE ?\n OR from_name LIKE ?\n OR snippet LIKE ?\n ORDER BY date DESC\n LIMIT 100\n `,\n )\n .all(pattern, pattern, pattern, pattern) as EmailRow[];\n\n return rows.map(mapRow);\n}\n\nexport async function getEmailById(id: string): Promise<EmailMessage | null> {\n const config = loadConfig();\n const sqlite = getSqlite(config.dbPath);\n const row = sqlite\n .prepare(\n `\n SELECT id, thread_id, from_address, from_name, to_addresses, subject, snippet, date,\n is_read, is_starred, label_ids, size_estimate, has_attachments, list_unsubscribe\n FROM emails\n WHERE id = ?\n `,\n )\n .get(id) as EmailRow | undefined;\n\n return row ? mapRow(row) : null;\n}\n","import { loadConfig } from \"../../config.js\";\nimport { getSqlite } from \"../db/client.js\";\nimport { getGmailTransport } from \"../gmail/transport.js\";\nimport { batchGetMessages } from \"../gmail/messages.js\";\nimport type { EmailMessage, SyncResult } from \"../gmail/types.js\";\n\nexport type ProgressCallback = (synced: number, total: number | null) => void;\nexport type SyncProgressPhase =\n | \"starting\"\n | \"checking_history\"\n | \"fetching_messages\"\n | \"applying_changes\"\n | \"finalizing\"\n | \"fallback\";\n\nexport interface SyncProgressEvent {\n mode: \"full\" | \"incremental\";\n phase: SyncProgressPhase;\n synced: number;\n total: number | null;\n detail: string;\n}\n\nexport type SyncProgressEventCallback = (event: SyncProgressEvent) => void;\n\ntype SyncStateRow = {\n account_email: string | null;\n history_id: string | null;\n last_full_sync: number | null;\n last_incremental_sync: number | null;\n total_messages: number | null;\n full_sync_cursor: string | null;\n full_sync_processed: number | null;\n full_sync_total: number | null;\n};\n\nexport interface AccountCacheReconciliationResult {\n cleared: boolean;\n reason: \"account_switched\" | \"legacy_unscoped_cache\" | null;\n previousEmail: string | null;\n}\n\nfunction upsertEmails(dbPath: string, messages: EmailMessage[]): void {\n if (messages.length === 0) {\n return;\n }\n\n const sqlite = getSqlite(dbPath);\n const statement = sqlite.prepare(`\n INSERT INTO emails (\n id, thread_id, from_address, from_name, to_addresses, subject, snippet, date,\n is_read, is_starred, label_ids, size_estimate, has_attachments, list_unsubscribe, synced_at\n ) VALUES (\n @id, @thread_id, @from_address, @from_name, @to_addresses, @subject, @snippet, @date,\n @is_read, @is_starred, @label_ids, @size_estimate, @has_attachments, @list_unsubscribe, @synced_at\n )\n ON CONFLICT(id) DO UPDATE SET\n thread_id = excluded.thread_id,\n from_address = excluded.from_address,\n from_name = excluded.from_name,\n to_addresses = excluded.to_addresses,\n subject = excluded.subject,\n snippet = excluded.snippet,\n date = excluded.date,\n is_read = excluded.is_read,\n is_starred = excluded.is_starred,\n label_ids = excluded.label_ids,\n size_estimate = excluded.size_estimate,\n has_attachments = excluded.has_attachments,\n list_unsubscribe = excluded.list_unsubscribe,\n synced_at = excluded.synced_at\n `);\n\n const now = Date.now();\n const transaction = sqlite.transaction((emails: EmailMessage[]) => {\n for (const message of emails) {\n statement.run({\n id: message.id,\n thread_id: message.threadId,\n from_address: message.fromAddress,\n from_name: message.fromName,\n to_addresses: JSON.stringify(message.toAddresses),\n subject: message.subject,\n snippet: message.snippet,\n date: message.date,\n is_read: message.isRead ? 1 : 0,\n is_starred: message.isStarred ? 1 : 0,\n label_ids: JSON.stringify(message.labelIds),\n size_estimate: message.sizeEstimate,\n has_attachments: message.hasAttachments ? 1 : 0,\n list_unsubscribe: message.listUnsubscribe,\n synced_at: now,\n });\n }\n });\n\n transaction(messages);\n}\n\nfunction deleteEmails(dbPath: string, ids: string[]): void {\n if (ids.length === 0) {\n return;\n }\n\n const sqlite = getSqlite(dbPath);\n const statement = sqlite.prepare(`DELETE FROM emails WHERE id = ?`);\n const transaction = sqlite.transaction((messageIds: string[]) => {\n for (const id of messageIds) {\n statement.run(id);\n }\n });\n transaction(ids);\n}\n\nfunction getSyncState(dbPath: string): SyncStateRow {\n const sqlite = getSqlite(dbPath);\n const row = sqlite\n .prepare(\n `SELECT account_email, history_id, last_full_sync, last_incremental_sync, total_messages, full_sync_cursor, full_sync_processed, full_sync_total FROM sync_state WHERE id = 1`,\n )\n .get() as SyncStateRow | undefined;\n\n return (\n row || {\n account_email: null,\n history_id: null,\n last_full_sync: null,\n last_incremental_sync: null,\n total_messages: 0,\n full_sync_cursor: null,\n full_sync_processed: 0,\n full_sync_total: 0,\n }\n );\n}\n\nfunction saveSyncState(\n dbPath: string,\n updates: Partial<SyncStateRow>,\n): void {\n const current = getSyncState(dbPath);\n const sqlite = getSqlite(dbPath);\n const next = {\n account_email: Object.prototype.hasOwnProperty.call(updates, \"account_email\")\n ? updates.account_email ?? null\n : current.account_email,\n history_id: Object.prototype.hasOwnProperty.call(updates, \"history_id\")\n ? updates.history_id ?? null\n : current.history_id,\n last_full_sync: Object.prototype.hasOwnProperty.call(updates, \"last_full_sync\")\n ? updates.last_full_sync ?? null\n : current.last_full_sync,\n last_incremental_sync: Object.prototype.hasOwnProperty.call(updates, \"last_incremental_sync\")\n ? updates.last_incremental_sync ?? null\n : current.last_incremental_sync,\n total_messages: Object.prototype.hasOwnProperty.call(updates, \"total_messages\")\n ? updates.total_messages ?? 0\n : current.total_messages,\n full_sync_cursor: Object.prototype.hasOwnProperty.call(updates, \"full_sync_cursor\")\n ? updates.full_sync_cursor ?? null\n : current.full_sync_cursor,\n full_sync_processed: Object.prototype.hasOwnProperty.call(updates, \"full_sync_processed\")\n ? updates.full_sync_processed ?? 0\n : current.full_sync_processed,\n full_sync_total: Object.prototype.hasOwnProperty.call(updates, \"full_sync_total\")\n ? updates.full_sync_total ?? 0\n : current.full_sync_total,\n };\n sqlite\n .prepare(\n `\n UPDATE sync_state\n SET account_email = ?,\n history_id = ?,\n last_full_sync = ?,\n last_incremental_sync = ?,\n total_messages = ?,\n full_sync_cursor = ?,\n full_sync_processed = ?,\n full_sync_total = ?\n WHERE id = 1\n `,\n )\n .run(\n next.account_email,\n next.history_id,\n next.last_full_sync,\n next.last_incremental_sync,\n next.total_messages,\n next.full_sync_cursor,\n next.full_sync_processed,\n next.full_sync_total,\n );\n}\n\nfunction clearCachedEmailData(dbPath: string): void {\n const sqlite = getSqlite(dbPath);\n sqlite.exec(`\n DELETE FROM emails;\n DELETE FROM newsletter_senders;\n `);\n}\n\nfunction clearAccountScopedState(dbPath: string, nextAccountEmail: string | null): void {\n const sqlite = getSqlite(dbPath);\n sqlite.exec(`\n DELETE FROM emails;\n DELETE FROM newsletter_senders;\n DELETE FROM execution_items;\n DELETE FROM execution_runs;\n `);\n\n sqlite\n .prepare(\n `\n UPDATE sync_state\n SET account_email = ?,\n history_id = NULL,\n last_full_sync = NULL,\n last_incremental_sync = NULL,\n total_messages = 0,\n full_sync_cursor = NULL,\n full_sync_processed = 0,\n full_sync_total = 0\n WHERE id = 1\n `,\n )\n .run(nextAccountEmail);\n}\n\nfunction resetFullSyncProgress(dbPath: string): void {\n saveSyncState(dbPath, {\n full_sync_cursor: null,\n full_sync_processed: 0,\n full_sync_total: 0,\n });\n}\n\nexport function reconcileCacheForAuthenticatedAccount(\n dbPath: string,\n authenticatedEmail: string | null | undefined,\n options?: { clearLegacyUnscoped?: boolean },\n): AccountCacheReconciliationResult {\n const normalizedEmail =\n authenticatedEmail && authenticatedEmail !== \"unknown\"\n ? authenticatedEmail\n : null;\n const state = getSyncState(dbPath);\n const sqlite = getSqlite(dbPath);\n const cachedEmailCount = (\n sqlite.prepare(\"SELECT COUNT(*) as count FROM emails\").get() as { count: number }\n ).count;\n\n if (!normalizedEmail) {\n return {\n cleared: false,\n reason: null,\n previousEmail: state.account_email,\n };\n }\n\n if (state.account_email && state.account_email !== normalizedEmail) {\n clearAccountScopedState(dbPath, normalizedEmail);\n return {\n cleared: true,\n reason: \"account_switched\",\n previousEmail: state.account_email,\n };\n }\n\n if (!state.account_email && cachedEmailCount > 0 && options?.clearLegacyUnscoped) {\n clearAccountScopedState(dbPath, normalizedEmail);\n return {\n cleared: true,\n reason: \"legacy_unscoped_cache\",\n previousEmail: null,\n };\n }\n\n if (state.account_email !== normalizedEmail) {\n saveSyncState(dbPath, { account_email: normalizedEmail });\n }\n\n return {\n cleared: false,\n reason: null,\n previousEmail: state.account_email,\n };\n}\n\nexport async function fullSync(\n onProgress?: ProgressCallback,\n onEvent?: SyncProgressEventCallback,\n): Promise<SyncResult> {\n const config = loadConfig();\n const transport = await getGmailTransport(config);\n const profile = await transport.getProfile();\n const accountEmail = profile.emailAddress || null;\n const priorState = getSyncState(config.dbPath);\n const accountReconciliation = reconcileCacheForAuthenticatedAccount(\n config.dbPath,\n accountEmail,\n { clearLegacyUnscoped: true },\n );\n const pageSize = Math.min(config.sync.pageSize, 100);\n const maxMessages = config.sync.maxMessages;\n const resumableSync =\n !accountReconciliation.cleared &&\n priorState.account_email === accountEmail &&\n !priorState.history_id &&\n ((priorState.full_sync_cursor && priorState.full_sync_cursor.length > 0) ||\n (priorState.full_sync_processed || 0) > 0);\n let pageToken = resumableSync ? priorState.full_sync_cursor || undefined : undefined;\n let processed = resumableSync ? priorState.full_sync_processed || 0 : 0;\n let added = 0;\n let updated = 0;\n let latestHistoryId = profile.historyId || getSyncState(config.dbPath).history_id || \"\";\n const knownTotalMessages = profile.messagesTotal ?? priorState.full_sync_total ?? null;\n\n if (!resumableSync) {\n clearCachedEmailData(config.dbPath);\n resetFullSyncProgress(config.dbPath);\n }\n\n onEvent?.({\n mode: \"full\",\n phase: \"starting\",\n synced: processed,\n total: knownTotalMessages,\n detail: resumableSync\n ? `Resuming full mailbox sync… ${processed}${knownTotalMessages ? ` / ${knownTotalMessages}` : \"\"}`\n : accountReconciliation.cleared\n ? \"Starting full mailbox sync after resetting the local cache for this account…\"\n : \"Starting full mailbox sync…\",\n });\n onProgress?.(processed, knownTotalMessages);\n\n do {\n const response = await transport.listMessages({\n maxResults: pageSize,\n pageToken,\n });\n\n pageToken = response.nextPageToken || undefined;\n\n const ids = (response.messages || [])\n .map((message) => message.id)\n .filter(Boolean) as string[];\n\n if (ids.length === 0) {\n break;\n }\n\n onEvent?.({\n mode: \"full\",\n phase: \"fetching_messages\",\n synced: processed,\n total: knownTotalMessages,\n detail: \"Fetching message metadata…\",\n });\n\n const processedBeforeBatch = processed;\n const messages = await batchGetMessages(ids, (completedInBatch) => {\n const synced = processedBeforeBatch + completedInBatch;\n const total = knownTotalMessages !== null\n ? Math.max(knownTotalMessages, synced)\n : null;\n\n onProgress?.(synced, total);\n onEvent?.({\n mode: \"full\",\n phase: \"fetching_messages\",\n synced,\n total,\n detail: `Fetching mailbox metadata… ${synced}${total ? ` / ${total}` : \"\"}`,\n });\n });\n upsertEmails(config.dbPath, messages);\n\n processed += messages.length;\n updated += messages.length;\n added += messages.length;\n saveSyncState(config.dbPath, {\n account_email: accountEmail,\n total_messages: processed,\n full_sync_cursor: pageToken || null,\n full_sync_processed: processed,\n full_sync_total: knownTotalMessages ?? processed,\n });\n onProgress?.(\n processed,\n knownTotalMessages !== null ? Math.max(knownTotalMessages, processed) : null,\n );\n\n if (maxMessages && processed >= maxMessages) {\n pageToken = undefined;\n }\n } while (pageToken);\n\n onEvent?.({\n mode: \"full\",\n phase: \"finalizing\",\n synced: processed,\n total: knownTotalMessages !== null ? Math.max(knownTotalMessages, processed) : processed,\n detail: \"Finalizing full sync…\",\n });\n saveSyncState(config.dbPath, {\n account_email: accountEmail,\n history_id: latestHistoryId,\n last_full_sync: Date.now(),\n total_messages: processed,\n full_sync_cursor: null,\n full_sync_processed: 0,\n full_sync_total: 0,\n });\n\n return {\n messagesProcessed: processed,\n messagesAdded: added,\n messagesUpdated: updated,\n historyId: latestHistoryId,\n mode: \"full\",\n usedHistoryFallback: false,\n };\n}\n\nfunction isStaleHistoryError(error: unknown): boolean {\n const status = (error as { code?: number; status?: number }).code ||\n (error as { code?: number; status?: number }).status;\n return status === 404;\n}\n\nexport async function incrementalSync(\n onProgress?: ProgressCallback,\n onEvent?: SyncProgressEventCallback,\n): Promise<SyncResult> {\n const config = loadConfig();\n const transport = await getGmailTransport(config);\n const profile = await transport.getProfile();\n const accountReconciliation = reconcileCacheForAuthenticatedAccount(\n config.dbPath,\n profile.emailAddress || null,\n { clearLegacyUnscoped: true },\n );\n const state = getSyncState(config.dbPath);\n\n if (accountReconciliation.cleared || !state.history_id) {\n return fullSync(onProgress, onEvent);\n }\n\n try {\n onEvent?.({\n mode: \"incremental\",\n phase: \"checking_history\",\n synced: 0,\n total: null,\n detail: \"Checking Gmail history for changes…\",\n });\n\n const response = await transport.listHistory({\n startHistoryId: state.history_id,\n maxResults: config.sync.pageSize,\n historyTypes: [\n \"messageAdded\",\n \"labelAdded\",\n \"labelRemoved\",\n \"messageDeleted\",\n ],\n });\n\n const history = response.history || [];\n const touchedIds = new Set<string>();\n const deletedIds = new Set<string>();\n\n for (const entry of history) {\n for (const item of entry.messagesAdded || []) {\n if (item.message?.id) {\n touchedIds.add(item.message.id);\n }\n }\n\n for (const item of entry.labelsAdded || []) {\n if (item.message?.id) {\n touchedIds.add(item.message.id);\n }\n }\n\n for (const item of entry.labelsRemoved || []) {\n if (item.message?.id) {\n touchedIds.add(item.message.id);\n }\n }\n\n for (const item of entry.messagesDeleted || []) {\n if (item.message?.id) {\n deletedIds.add(item.message.id);\n }\n }\n }\n\n for (const id of deletedIds) {\n touchedIds.delete(id);\n }\n\n const totalChanges = touchedIds.size + deletedIds.size;\n\n onEvent?.({\n mode: \"incremental\",\n phase: \"fetching_messages\",\n synced: 0,\n total: totalChanges,\n detail:\n totalChanges === 0\n ? \"No changes found.\"\n : `Refreshing ${touchedIds.size} changed emails and ${deletedIds.size} deletions…`,\n });\n\n const refreshed = await batchGetMessages([...touchedIds], (completed) => {\n onProgress?.(completed, totalChanges);\n onEvent?.({\n mode: \"incremental\",\n phase: \"fetching_messages\",\n synced: completed,\n total: totalChanges,\n detail: `Refreshing changed emails… ${completed}${totalChanges ? ` / ${totalChanges}` : \"\"}`,\n });\n });\n\n onEvent?.({\n mode: \"incremental\",\n phase: \"applying_changes\",\n synced: refreshed.length,\n total: totalChanges,\n detail: \"Applying Gmail changes to the local cache…\",\n });\n\n upsertEmails(config.dbPath, refreshed);\n deleteEmails(config.dbPath, [...deletedIds]);\n\n onProgress?.(totalChanges, totalChanges || null);\n onEvent?.({\n mode: \"incremental\",\n phase: \"finalizing\",\n synced: totalChanges,\n total: totalChanges || null,\n detail: \"Finalizing incremental sync…\",\n });\n\n const latestHistoryId = response.historyId || state.history_id;\n const totalMessagesRow = getSqlite(config.dbPath)\n .prepare(`SELECT COUNT(*) as count FROM emails`)\n .get() as { count: number };\n saveSyncState(config.dbPath, {\n account_email: profile.emailAddress || null,\n history_id: latestHistoryId,\n last_incremental_sync: Date.now(),\n total_messages: totalMessagesRow.count,\n full_sync_cursor: null,\n full_sync_processed: 0,\n full_sync_total: 0,\n });\n\n return {\n messagesProcessed: refreshed.length + deletedIds.size,\n messagesAdded: refreshed.length,\n messagesUpdated: refreshed.length,\n historyId: latestHistoryId,\n mode: \"incremental\",\n usedHistoryFallback: false,\n };\n } catch (error) {\n if (!isStaleHistoryError(error)) {\n throw error;\n }\n\n console.warn(\n `Stored Gmail historyId ${state.history_id} is stale; falling back to full sync.`,\n );\n onEvent?.({\n mode: \"incremental\",\n phase: \"fallback\",\n synced: 0,\n total: null,\n detail: \"History checkpoint expired. Falling back to a full sync…\",\n });\n const result = await fullSync(onProgress, onEvent);\n\n return {\n ...result,\n usedHistoryFallback: true,\n };\n }\n}\n\nexport async function getSyncStatus(): Promise<{\n accountEmail: string | null;\n historyId: string | null;\n lastFullSync: number | null;\n lastIncrementalSync: number | null;\n totalMessages: number;\n fullSyncProcessed: number;\n fullSyncTotal: number | null;\n fullSyncResumable: boolean;\n}> {\n const config = loadConfig();\n const state = getSyncState(config.dbPath);\n\n return {\n accountEmail: state.account_email,\n historyId: state.history_id,\n lastFullSync: state.last_full_sync,\n lastIncrementalSync: state.last_incremental_sync,\n totalMessages: state.total_messages || 0,\n fullSyncProcessed: state.full_sync_processed || 0,\n fullSyncTotal: state.full_sync_total || null,\n fullSyncResumable: Boolean((state.full_sync_cursor && state.full_sync_cursor.length > 0) || (state.full_sync_processed || 0) > 0),\n };\n}\n"],"mappings":"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","names":["z","dirname","resolve","resolve","dirname","now","existsSync","dirname","OAuth2Client","OAuth2Client","resolve","text","resolve","text","index","label","index","resolveContext","emails","resolveContext","resolveContext","getDatabase","now","now","randomUUID","randomUUID","now","randomUUID","readFile","join","readFile","join","getDatabase","serializeJson","now","randomUUID","getDatabase","rules","getDatabase","parseJsonArray","rowToEmail","emails","rules","resolveContext","upsertEmails","now","emails","DAY_MS","text","z","rules"]}
|