aamp-openclaw-plugin 0.1.21 → 0.1.24
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/bin/aamp-openclaw-plugin.mjs +66 -16
- package/dist/index.js +31 -11
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../sdk/src/jmap-push.ts", "../../sdk/src/types.ts", "../../sdk/src/parser.ts", "../../sdk/src/tiny-emitter.ts", "../../sdk/src/smtp-sender.ts", "../../sdk/src/client.ts", "../src/file-store.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * JMAP WebSocket Push Client\n *\n * Connects to Stalwart's JMAP WebSocket endpoint and subscribes to\n * Email StateChange events. When a new email arrives in the agent's\n * mailbox, fetches it via JMAP and emits the parsed AAMP headers.\n *\n * Protocol: RFC 8887 (JMAP over WebSocket)\n * Ref: https://www.rfc-editor.org/rfc/rfc8887\n */\n\nimport WebSocket from 'ws'\nimport { parseAampHeaders } from './parser.js'\nimport type { AampMessage, HumanReply, TaskAck, TaskDispatch, TaskHelp, TaskResult } from './types.js'\nimport { TinyEmitter } from './tiny-emitter.js'\n\ninterface JmapSession {\n capabilities: Record<string, unknown>\n accounts: Record<string, { name: string; isPrimary: boolean; accountCapabilities: Record<string, unknown> }>\n primaryAccounts: Record<string, string>\n username: string\n apiUrl: string\n downloadUrl: string\n uploadUrl: string\n eventSourceUrl: string\n state: string\n}\n\ninterface JmapStateChange {\n '@type': 'StateChange'\n changed: Record<string, Record<string, string>>\n pushState?: string\n}\n\ninterface JmapEmail {\n id: string\n blobId: string\n threadId: string\n mailboxIds: Record<string, boolean>\n subject: string\n from: Array<{ email: string; name?: string }>\n to: Array<{ email: string; name?: string }>\n replyTo?: Array<{ email: string; name?: string }>\n messageId?: string[]\n headers: Array<{ name: string; value: string }>\n receivedAt: string\n size: number\n /** Plain-text body parts (JMAP bodyStructure) */\n textBody?: Array<{ partId: string; type: string }>\n /** Decoded body values keyed by partId */\n bodyValues?: Record<string, { value: string; isEncodingProblem?: boolean; isTruncated?: boolean }>\n /** JMAP attachments (non-inline parts) */\n attachments?: Array<{\n blobId: string\n type: string\n name: string | null\n size: number\n }>\n}\n\ninterface JmapMethodResponse {\n methodResponses: Array<[string, Record<string, unknown>, string]>\n}\n\nfunction describeError(err: unknown): string {\n if (!(err instanceof Error)) return String(err)\n\n const parts = [err.message]\n const details = err as Error & {\n code?: string\n errno?: number | string\n syscall?: string\n address?: string\n port?: number\n cause?: unknown\n }\n\n if (details.code) parts.push(`code=${details.code}`)\n if (details.errno !== undefined) parts.push(`errno=${details.errno}`)\n if (details.syscall) parts.push(`syscall=${details.syscall}`)\n if (details.address) parts.push(`address=${details.address}`)\n if (details.port !== undefined) parts.push(`port=${details.port}`)\n\n if (details.cause instanceof Error) {\n parts.push(`cause=${describeError(details.cause)}`)\n } else if (details.cause !== undefined) {\n parts.push(`cause=${String(details.cause)}`)\n }\n\n return parts.join(' | ')\n}\n\ntype JmapPushEvents = {\n 'task.dispatch': (task: TaskDispatch) => void\n 'task.result': (result: TaskResult) => void\n 'task.help': (help: TaskHelp) => void\n 'task.ack': (ack: TaskAck) => void\n reply: (reply: HumanReply) => void\n connected: () => void\n disconnected: (reason: string) => void\n error: (err: Error) => void\n _autoAck: (payload: { to: string; taskId: string; messageId: string }) => void\n}\n\nexport class JmapPushClient extends TinyEmitter<JmapPushEvents> {\n private ws: WebSocket | null = null\n private session: JmapSession | null = null\n private reconnectTimer: NodeJS.Timeout | null = null\n private pollTimer: NodeJS.Timeout | null = null\n private pingTimer: NodeJS.Timeout | null = null\n private safetySyncTimer: NodeJS.Timeout | null = null\n private readonly seenMessageIds = new Set<string>()\n private connected = false\n private pollingActive = false\n private running = false\n private connecting = false\n /** JMAP Email state \u2014 tracks processed position; null = not yet initialized */\n private emailState: string | null = null\n private readonly startedAtMs = Date.now()\n\n private readonly email: string\n private readonly password: string\n private readonly jmapUrl: string\n private readonly reconnectInterval: number\n private readonly rejectUnauthorized: boolean\n private readonly pingIntervalMs = 5000\n private readonly safetySyncIntervalMs = 5000\n\n constructor(opts: {\n email: string\n password: string\n jmapUrl: string\n reconnectInterval?: number\n /** Whether to reject unauthorized TLS certificates (default: true) */\n rejectUnauthorized?: boolean\n }) {\n super()\n this.email = opts.email\n this.password = opts.password\n this.jmapUrl = opts.jmapUrl.replace(/\\/$/, '')\n this.reconnectInterval = opts.reconnectInterval ?? 5000\n this.rejectUnauthorized = opts.rejectUnauthorized ?? true\n }\n\n /**\n * Start the JMAP Push listener\n */\n async start(): Promise<void> {\n this.running = true\n this.startSafetySync()\n await this.connect()\n }\n\n /**\n * Stop the JMAP Push listener\n */\n stop(): void {\n this.running = false\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n if (this.pollTimer) {\n clearTimeout(this.pollTimer)\n this.pollTimer = null\n }\n if (this.pingTimer) {\n clearInterval(this.pingTimer)\n this.pingTimer = null\n }\n if (this.safetySyncTimer) {\n clearInterval(this.safetySyncTimer)\n this.safetySyncTimer = null\n }\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n this.connected = false\n this.pollingActive = false\n this.connecting = false\n }\n\n private getAuthHeader(): string {\n const creds = `${this.email}:${this.password}`\n return `Basic ${Buffer.from(creds).toString('base64')}`\n }\n\n /**\n * Fetch the JMAP session object\n */\n private async fetchSession(): Promise<JmapSession> {\n const url = `${this.jmapUrl}/.well-known/jmap`\n let res: Response\n try {\n res = await fetch(url, {\n headers: { Authorization: this.getAuthHeader() },\n })\n } catch (err) {\n throw new Error(`fetchSession ${url} failed: ${describeError(err)}`)\n }\n\n if (!res.ok) {\n throw new Error(`Failed to fetch JMAP session: ${res.status} ${res.statusText}`)\n }\n\n return res.json() as Promise<JmapSession>\n }\n\n /**\n * Perform a JMAP API call\n */\n private async jmapCall(\n methods: Array<[string, Record<string, unknown>, string]>,\n ): Promise<JmapMethodResponse> {\n if (!this.session) throw new Error('No JMAP session')\n\n // Use the configured jmapUrl (external hostname) rather than session.apiUrl\n // which Stalwart populates with its own internal URL (e.g. http://aamp.local:8080/jmap)\n // and is unreachable when running behind a proxy.\n const apiUrl = `${this.jmapUrl}/jmap/`\n let res: Response\n try {\n res = await fetch(apiUrl, {\n method: 'POST',\n headers: {\n Authorization: this.getAuthHeader(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n using: [\n 'urn:ietf:params:jmap:core',\n 'urn:ietf:params:jmap:mail',\n ],\n methodCalls: methods,\n }),\n })\n } catch (err) {\n throw new Error(`jmapCall ${apiUrl} failed: ${describeError(err)}`)\n }\n\n if (!res.ok) {\n throw new Error(`JMAP API call failed: ${res.status}`)\n }\n\n return res.json() as Promise<JmapMethodResponse>\n }\n\n /**\n * Initialize emailState by fetching the current state without loading any emails.\n * Called on first connect so we only process emails that arrive AFTER this point.\n */\n private async initEmailState(accountId: string): Promise<void> {\n const response = await this.jmapCall([\n ['Email/get', { accountId, ids: [] }, 'g0'],\n ])\n const getResp = response.methodResponses.find(([name]) => name === 'Email/get')\n if (getResp) {\n this.emailState = (getResp[1] as { state?: string }).state ?? null\n }\n }\n\n /**\n * Fetch only emails created since `sinceState` using Email/changes.\n * Updates `this.emailState` to the new state after fetching.\n * Returns [] and resets state if the server cannot calculate changes (state too old).\n */\n private async fetchEmailsSince(accountId: string, sinceState: string): Promise<JmapEmail[]> {\n const changesResp = await this.jmapCall([\n ['Email/changes', { accountId, sinceState, maxChanges: 50 }, 'c1'],\n ])\n\n const changesResult = changesResp.methodResponses.find(([name]) => name === 'Email/changes')\n\n // Handle server error \u2014 e.g. \"cannotCalculateChanges\" when state is too old\n if (!changesResult || changesResult[0] === 'error') {\n await this.initEmailState(accountId)\n return []\n }\n\n const changes = changesResult[1] as {\n created?: string[]\n newState?: string\n hasMoreChanges?: boolean\n }\n\n if (changes.newState) {\n this.emailState = changes.newState\n }\n\n const newIds = changes.created ?? []\n if (newIds.length === 0) return []\n\n const emailResp = await this.jmapCall([\n [\n 'Email/get',\n {\n accountId,\n ids: newIds,\n properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],\n fetchTextBodyValues: true,\n maxBodyValueBytes: 262144,\n },\n 'g1',\n ],\n ])\n\n const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get')\n if (!getResult) return []\n\n const data = getResult[1] as { list?: JmapEmail[] }\n return data.list ?? []\n }\n\n /**\n * Process a received email.\n *\n * Priority:\n * 1. If X-AAMP-Intent is present \u2192 emit typed AAMP event (task.dispatch / task.result / task.help)\n * 2. If In-Reply-To is present \u2192 emit 'reply' event so the application layer can\n * resolve the thread (inReplyTo \u2192 taskId via Redis/DB) and handle human replies.\n * 3. Otherwise \u2192 ignore (not an AAMP-related email)\n */\n private processEmail(email: JmapEmail): void {\n // Build lowercase header map from JMAP header array\n const headerMap: Record<string, string> = {}\n for (const h of email.headers ?? []) {\n headerMap[h.name.toLowerCase()] = h.value.trim()\n }\n\n const fromAddr = email.from?.[0]?.email ?? ''\n const toAddr = email.to?.[0]?.email ?? ''\n const messageId = email.messageId?.[0] ?? email.id\n\n if (this.seenMessageIds.has(messageId)) return\n this.seenMessageIds.add(messageId)\n\n // \u2500\u2500 Path 1: AAMP-tagged email \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const msg: AampMessage | null = parseAampHeaders({\n from: fromAddr,\n to: toAddr,\n messageId,\n subject: email.subject ?? '',\n headers: headerMap,\n })\n\n if (msg && 'intent' in msg) {\n // Attach email body text (task description) to all AAMP messages\n const aampTextPartId = email.textBody?.[0]?.partId\n const aampBodyText = aampTextPartId ? (email.bodyValues?.[aampTextPartId]?.value ?? '').trim() : ''\n ;(msg as unknown as Record<string, unknown>).bodyText = aampBodyText\n\n // Attach received attachment metadata (blobId-based, downloadable via downloadBlob)\n const receivedAttachments = (email.attachments ?? []).map(a => ({\n filename: a.name ?? 'attachment',\n contentType: a.type,\n size: a.size,\n blobId: a.blobId,\n }))\n if (receivedAttachments.length > 0) {\n ;(msg as unknown as Record<string, unknown>).attachments = receivedAttachments\n }\n\n // Auto-ACK for dispatches \u2014 AampClient handles the actual sending\n if ((msg as { intent: string }).intent === 'task.dispatch') {\n this.emit('_autoAck', { to: fromAddr, taskId: (msg as { taskId: string }).taskId, messageId })\n }\n\n const aampMsg = msg as Exclude<AampMessage, HumanReply>\n switch (aampMsg.intent) {\n case 'task.dispatch':\n this.emit('task.dispatch', aampMsg)\n break\n case 'task.result':\n this.emit('task.result', aampMsg)\n break\n case 'task.help':\n this.emit('task.help', aampMsg)\n break\n case 'task.ack':\n this.emit('task.ack', aampMsg)\n break\n }\n return\n }\n\n // \u2500\u2500 Path 2: standard email reply \u2014 In-Reply-To fallback \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Standard email clients automatically set In-Reply-To when replying.\n // We strip angle brackets (<msgid@host>) to get the bare Message-ID.\n const rawInReplyTo = headerMap['in-reply-to'] ?? ''\n if (!rawInReplyTo) return // unrelated email, ignore\n\n // Handle \"References\" chain: prefer the last (most recent) Message-ID\n // so multi-turn threads still resolve to the correct task.\n const rawReferences = headerMap['references'] ?? ''\n const referencesIds = rawReferences\n .split(/\\s+/)\n .map((s) => s.replace(/[<>]/g, '').trim())\n .filter(Boolean)\n\n const inReplyTo = rawInReplyTo.replace(/[<>]/g, '').trim()\n\n // Extract plain-text body if available (fetched via fetchTextBodyValues)\n const textPartId = email.textBody?.[0]?.partId\n const bodyText = textPartId ? (email.bodyValues?.[textPartId]?.value ?? '').trim() : ''\n\n const reply: HumanReply = {\n inReplyTo,\n messageId,\n from: fromAddr,\n to: toAddr,\n subject: email.subject ?? '',\n bodyText,\n }\n\n // Also expose the full References chain so callers can walk the thread if needed\n if (referencesIds.length > 0) {\n Object.assign(reply, { references: referencesIds })\n }\n\n this.emit('reply', reply)\n }\n\n private async fetchRecentEmails(accountId: string): Promise<JmapEmail[]> {\n const queryResp = await this.jmapCall([\n [\n 'Email/query',\n {\n accountId,\n sort: [{ property: 'receivedAt', isAscending: false }],\n limit: 20,\n },\n 'q1',\n ],\n ])\n\n const queryResult = queryResp.methodResponses.find(([name]) => name === 'Email/query')\n if (!queryResult) return []\n\n const ids = ((queryResult[1] as { ids?: string[] }).ids ?? []).slice(0, 20)\n if (ids.length === 0) return []\n\n const emailResp = await this.jmapCall([\n [\n 'Email/get',\n {\n accountId,\n ids,\n properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],\n fetchTextBodyValues: true,\n maxBodyValueBytes: 262144,\n },\n 'gRecent',\n ],\n ])\n\n const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get')\n if (!getResult) return []\n\n return (getResult[1] as { list?: JmapEmail[] }).list ?? []\n }\n\n private shouldProcessBootstrapEmail(email: JmapEmail): boolean {\n const receivedAtMs = new Date(email.receivedAt).getTime()\n // Keep a small grace window for mail that arrived during startup / reconnect races,\n // but do not replay older historical mailbox contents as fresh tasks.\n return Number.isFinite(receivedAtMs) && receivedAtMs >= this.startedAtMs - 15_000\n }\n\n /**\n * Connect to JMAP WebSocket\n */\n private async connect(): Promise<void> {\n if (this.connecting || !this.running) return\n this.connecting = true\n\n try {\n this.session = await this.fetchSession()\n } catch (err) {\n this.connecting = false\n this.emit('error', new Error(`Failed to get JMAP session: ${(err as Error).message}`))\n this.startPolling('session fetch failed')\n this.scheduleReconnect()\n return\n }\n\n // Build WebSocket URL from the configured jmapUrl (the management-service proxy).\n // The management service exposes the standard external WebSocket path /jmap/ws\n // and proxies upgrades to Stalwart. We never use the session capability URL\n // directly because Stalwart populates it with its own internal hostname\n // (e.g. ws://aamp.local:8080/jmap/ws), which is unreachable from outside\n // the Docker / cluster network.\n const stalwartWsUrl = `${this.jmapUrl}/jmap/ws`\n .replace(/^https:\\/\\//, 'wss://')\n .replace(/^http:\\/\\//, 'ws://')\n\n this.ws = new WebSocket(stalwartWsUrl, 'jmap', {\n headers: {\n Authorization: this.getAuthHeader(),\n },\n perMessageDeflate: false,\n rejectUnauthorized: this.rejectUnauthorized,\n })\n\n this.ws.on('unexpected-response', (_req, res) => {\n this.connecting = false\n const headerSummary = Object.entries(res.headers)\n .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(', ') : (value ?? '')}`)\n .join('; ')\n this.startPolling(`websocket handshake failed: ${res.statusCode ?? 'unknown'}`)\n this.emit(\n 'error',\n new Error(\n `JMAP WebSocket handshake failed: ${res.statusCode ?? 'unknown'} ${res.statusMessage ?? ''}${headerSummary ? ` | headers: ${headerSummary}` : ''}`,\n ),\n )\n this.scheduleReconnect()\n })\n\n this.ws.on('open', async () => {\n this.connecting = false\n this.connected = true\n this.stopPolling()\n this.startPingHeartbeat()\n\n // On first connect (emailState is null), initialize state so we only\n // process emails arriving AFTER this point.\n // On reconnect, emailState is already set \u2014 Email/changes will catch up.\n const accountId = this.session?.primaryAccounts['urn:ietf:params:jmap:mail']\n if (accountId && this.emailState === null) {\n await this.initEmailState(accountId)\n }\n\n // Subscribe to Email state changes AFTER state is initialized\n this.ws!.send(\n JSON.stringify({\n '@type': 'WebSocketPushEnable',\n dataTypes: ['Email'],\n pushState: null,\n }),\n )\n\n this.emit('connected')\n })\n\n this.ws.on('pong', () => {\n // Receiving pong confirms the upstream and LB path are still alive.\n })\n\n this.ws.on('message', async (rawData: WebSocket.RawData) => {\n try {\n const msg = JSON.parse(rawData.toString()) as {\n '@type': string\n } & JmapStateChange\n\n if (msg['@type'] === 'StateChange') {\n await this.handleStateChange(msg)\n }\n } catch (err) {\n this.emit('error', new Error(`Failed to process JMAP push message: ${(err as Error).message}`))\n }\n })\n\n this.ws.on('close', (code, reason) => {\n this.connecting = false\n this.connected = false\n this.stopPingHeartbeat()\n const reasonStr = reason?.toString() ?? 'connection closed'\n this.startPolling(reasonStr)\n this.emit('disconnected', reasonStr)\n\n if (this.running) {\n this.scheduleReconnect()\n }\n })\n\n this.ws.on('error', (err) => {\n this.connecting = false\n this.stopPingHeartbeat()\n this.startPolling(err.message)\n this.emit('error', err)\n })\n }\n\n private startPingHeartbeat(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer)\n this.pingTimer = null\n }\n\n this.pingTimer = setInterval(() => {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n try {\n this.ws.ping()\n } catch (err) {\n this.emit('error', new Error(`Failed to send WebSocket ping: ${(err as Error).message}`))\n }\n }, this.pingIntervalMs)\n }\n\n private stopPingHeartbeat(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer)\n this.pingTimer = null\n }\n }\n\n private startSafetySync(): void {\n if (this.safetySyncTimer) return\n\n this.safetySyncTimer = setInterval(() => {\n if (!this.running) return\n\n void this.reconcileRecentEmails(20).catch((err) => {\n this.emit('error', new Error(`Safety reconcile failed: ${(err as Error).message}`))\n })\n }, this.safetySyncIntervalMs)\n }\n\n private async handleStateChange(stateChange: JmapStateChange): Promise<void> {\n if (!this.session) return\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n if (!accountId) return\n\n const changedAccount = stateChange.changed[accountId]\n if (!changedAccount?.Email) return\n\n try {\n if (this.emailState === null) {\n // State not yet initialized (race between open handler and first StateChange)\n // Just initialize and skip \u2014 next StateChange will use Email/changes properly\n await this.initEmailState(accountId)\n return\n }\n\n const emails = await this.fetchEmailsSince(accountId, this.emailState)\n for (const email of emails) {\n this.processEmail(email)\n }\n } catch (err) {\n this.emit('error', new Error(`Failed to fetch emails: ${(err as Error).message}`))\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null\n if (this.running) {\n await this.connect()\n }\n }, this.reconnectInterval)\n }\n\n isConnected(): boolean {\n return this.connected || this.pollingActive\n }\n\n isUsingPollingFallback(): boolean {\n return this.pollingActive && !this.connected\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearTimeout(this.pollTimer)\n this.pollTimer = null\n }\n this.pollingActive = false\n }\n\n private startPolling(reason: string): void {\n if (!this.running || this.pollingActive) return\n\n this.pollingActive = true\n this.emit('error', new Error(`JMAP WebSocket unavailable, falling back to polling: ${reason}`))\n this.emit('connected')\n\n const poll = async () => {\n if (!this.running || this.connected) {\n this.stopPolling()\n return\n }\n\n try {\n if (!this.session) {\n this.session = await this.fetchSession()\n }\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n ?? Object.keys(this.session.accounts)[0]\n\n if (!accountId) {\n throw new Error('No mail account available in JMAP session')\n }\n\n if (this.emailState === null) {\n const recentEmails = await this.fetchRecentEmails(accountId)\n for (const email of recentEmails.sort((a, b) => {\n const aTs = new Date(a.receivedAt).getTime()\n const bTs = new Date(b.receivedAt).getTime()\n return aTs - bTs\n })) {\n if (!this.shouldProcessBootstrapEmail(email)) continue\n this.processEmail(email)\n }\n await this.initEmailState(accountId)\n } else {\n const emails = await this.fetchEmailsSince(accountId, this.emailState)\n for (const email of emails) {\n this.processEmail(email)\n }\n }\n } catch (err) {\n this.emit('error', new Error(`Polling fallback failed: ${(err as Error).message}`))\n } finally {\n if (this.running && !this.connected) {\n this.pollTimer = setTimeout(poll, this.reconnectInterval)\n }\n }\n }\n\n this.pollTimer = setTimeout(poll, 0)\n }\n\n /**\n * Download a blob (attachment) by its JMAP blobId.\n * Returns the raw binary content as a Buffer.\n */\n async downloadBlob(blobId: string, filename?: string): Promise<Buffer> {\n if (!this.session) {\n // Fetch session on demand if not yet connected\n this.session = await this.fetchSession()\n }\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n ?? Object.keys(this.session.accounts)[0]\n\n // Build download URL from session template or fall back to standard JMAP path\n let downloadUrl = this.session.downloadUrl\n ?? `${this.jmapUrl}/jmap/download/{accountId}/{blobId}/{name}`\n\n // Replace session.downloadUrl host with our configured jmapUrl\n // (Stalwart may report an internal hostname unreachable from outside Docker)\n try {\n const parsed = new URL(downloadUrl)\n const configured = new URL(this.jmapUrl)\n parsed.protocol = configured.protocol\n parsed.host = configured.host\n downloadUrl = parsed.toString()\n } catch {\n // If URL parsing fails, use the template as-is\n }\n\n const safeFilename = filename ?? 'attachment'\n downloadUrl = downloadUrl\n .replace(/\\{accountId\\}|%7BaccountId%7D/gi, encodeURIComponent(accountId))\n .replace(/\\{blobId\\}|%7BblobId%7D/gi, encodeURIComponent(blobId))\n .replace(/\\{name\\}|%7Bname%7D/gi, encodeURIComponent(safeFilename))\n .replace(/\\{type\\}|%7Btype%7D/gi, 'application/octet-stream')\n\n // Retry with exponential backoff \u2014 the blob may not be immediately available\n // after the result email is observed (store/index write delay).\n const maxAttempts = 8\n let lastStatus: number | null = null\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const res = await fetch(downloadUrl, {\n headers: { Authorization: this.getAuthHeader() },\n })\n lastStatus = res.status\n if (res.ok) {\n const arrayBuffer = await res.arrayBuffer()\n return Buffer.from(arrayBuffer)\n }\n if (attempt < maxAttempts && (res.status === 404 || res.status === 429 || res.status === 503)) {\n console.warn(\n `[AAMP-SDK] blob download retry status=${res.status} attempt=${attempt}/${maxAttempts} url=${downloadUrl}`,\n )\n const delay = Math.min(1000 * Math.pow(2, attempt - 1), 15000) // 1s, 2s, 4s, 8s, 15s...\n await new Promise(r => setTimeout(r, delay))\n continue\n }\n console.error(\n `[AAMP-SDK] blob download failed status=${res.status} attempt=${attempt}/${maxAttempts} url=${downloadUrl}`,\n )\n throw new Error(\n `Blob download failed: status=${res.status} attempt=${attempt}/${maxAttempts} blobId=${blobId} filename=${filename ?? 'attachment'} url=${downloadUrl}`,\n )\n }\n throw new Error(\n `Blob download failed after retries: status=${lastStatus ?? 'unknown'} attempt=${maxAttempts}/${maxAttempts} blobId=${blobId} filename=${filename ?? 'attachment'} url=${downloadUrl}`,\n )\n }\n\n /**\n * Actively reconcile recent mailbox contents via JMAP HTTP.\n * Useful as a safety net when the WebSocket stays \"connected\"\n * but a notification is missed by an intermediate layer.\n */\n async reconcileRecentEmails(limit = 20): Promise<number> {\n if (!this.session) {\n this.session = await this.fetchSession()\n }\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n ?? Object.keys(this.session.accounts)[0]\n\n if (!accountId) {\n throw new Error('No mail account available in JMAP session')\n }\n\n const queryResp = await this.jmapCall([\n [\n 'Email/query',\n {\n accountId,\n sort: [{ property: 'receivedAt', isAscending: false }],\n limit,\n },\n 'qReconcile',\n ],\n ])\n\n const queryResult = queryResp.methodResponses.find(([name]) => name === 'Email/query')\n if (!queryResult) return 0\n\n const ids = ((queryResult[1] as { ids?: string[] }).ids ?? []).slice(0, limit)\n if (ids.length === 0) return 0\n\n const emailResp = await this.jmapCall([\n [\n 'Email/get',\n {\n accountId,\n ids,\n properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],\n fetchTextBodyValues: true,\n maxBodyValueBytes: 262144,\n },\n 'gReconcile',\n ],\n ])\n\n const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get')\n if (!getResult) return 0\n\n const emails = (getResult[1] as { list?: JmapEmail[] }).list ?? []\n for (const email of emails.sort((a, b) => {\n const aTs = new Date(a.receivedAt).getTime()\n const bTs = new Date(b.receivedAt).getTime()\n return aTs - bTs\n })) {\n if (!this.shouldProcessBootstrapEmail(email)) continue\n this.processEmail(email)\n }\n\n return emails.length\n }\n}\n", "/**\n * AAMP SDK Type Definitions\n */\n\nexport type AampIntent = 'task.dispatch' | 'task.result' | 'task.help' | 'task.ack'\n\nexport type TaskStatus =\n | 'pending'\n | 'running'\n | 'completed'\n | 'rejected'\n | 'failed'\n | 'timeout'\n | 'help_needed'\n\n// =====================================================\n// AAMP Header constants\n// =====================================================\nexport const AAMP_HEADER = {\n INTENT: 'X-AAMP-Intent',\n TASK_ID: 'X-AAMP-TaskId',\n TIMEOUT: 'X-AAMP-Timeout',\n CONTEXT_LINKS: 'X-AAMP-ContextLinks',\n DISPATCH_CONTEXT: 'X-AAMP-Dispatch-Context',\n STATUS: 'X-AAMP-Status',\n OUTPUT: 'X-AAMP-Output',\n ERROR_MSG: 'X-AAMP-ErrorMsg',\n STRUCTURED_RESULT: 'X-AAMP-StructuredResult',\n QUESTION: 'X-AAMP-Question',\n BLOCKED_REASON: 'X-AAMP-BlockedReason',\n SUGGESTED_OPTIONS: 'X-AAMP-SuggestedOptions',\n PARENT_TASK_ID: 'X-AAMP-ParentTaskId',\n} as const\n\nexport interface StructuredResultField {\n fieldKey: string\n fieldTypeKey: string\n value?: unknown\n fieldAlias?: string\n index?: string\n attachmentFilenames?: string[]\n}\n\n// =====================================================\n// Parsed AAMP headers for task.dispatch\n// =====================================================\nexport interface TaskDispatch {\n intent: 'task.dispatch'\n taskId: string\n title: string\n timeoutSecs: number\n contextLinks: string[]\n dispatchContext?: Record<string, string>\n parentTaskId?: string\n // Email metadata\n from: string\n to: string\n messageId: string\n subject: string\n /** Plain-text body of the email (task description) */\n bodyText: string\n /** Attachments received with this dispatch (use blobId to download) */\n attachments?: ReceivedAttachment[]\n}\n\n// =====================================================\n// Parsed AAMP headers for task.result\n// =====================================================\nexport interface TaskResult {\n intent: 'task.result'\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n structuredResult?: StructuredResultField[]\n from: string\n to: string\n messageId?: string\n /** True when the reply came from a standard email client (no X-AAMP-Intent header).\n * taskId was resolved via In-Reply-To \u2192 Message-ID reverse lookup. */\n isHumanReply?: boolean\n /** Attachments received with this result (use blobId to download) */\n attachments?: ReceivedAttachment[]\n}\n\n// =====================================================\n// Human reply via standard email client (no AAMP headers)\n// Emitted as 'reply' event when an email has In-Reply-To but no X-AAMP-Intent.\n// The application layer is responsible for resolving inReplyTo \u2192 taskId\n// (e.g. via Redis reverse index) and deciding how to handle it.\n// =====================================================\nexport interface HumanReply {\n /** Message-ID of the email being replied to \u2014 use this to look up the taskId */\n inReplyTo: string\n /** This reply email's own Message-ID */\n messageId: string\n from: string\n to: string\n subject: string\n /** Plain-text body of the reply */\n bodyText: string\n}\n\n// =====================================================\n// Parsed AAMP headers for task.help\n// =====================================================\nexport interface TaskHelp {\n intent: 'task.help'\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions: string[]\n from: string\n to: string\n messageId?: string\n}\n\n// =====================================================\n// Parsed AAMP headers for task.ack\n// =====================================================\nexport interface TaskAck {\n intent: 'task.ack'\n taskId: string\n from: string\n to: string\n messageId?: string\n}\n\n// =====================================================\n// Attachment types\n// =====================================================\n\n/** Attachment for sending (binary content) */\nexport interface AampAttachment {\n filename: string\n contentType: string\n content: Buffer | string // Buffer for binary, base64 string for REST API\n size?: number\n}\n\n/** Attachment metadata received via JMAP (use blobId to download) */\nexport interface ReceivedAttachment {\n filename: string\n contentType: string\n size: number\n blobId: string\n}\n\nexport type AampMessage = TaskDispatch | TaskResult | TaskHelp | TaskAck | HumanReply\n\n// =====================================================\n// SDK Configuration\n// =====================================================\nexport interface AampClientConfig {\n /** Node email address, e.g. codereviewer-abc123@aamp.yourdomain.com */\n email: string\n\n /** Base64(email:smtpPassword) \u2014 returned by management service on agent creation */\n jmapToken: string\n\n /** Stalwart base URL, e.g. http://localhost:8080 */\n jmapUrl: string\n\n /** Optional HTTP send base URL. Defaults to jmapUrl and is used for same-domain send fallback via /api/send. */\n httpSendBaseUrl?: string\n\n /** SMTP submission host */\n smtpHost: string\n\n /** SMTP submission port (default: 587) */\n smtpPort?: number\n\n /** SMTP password (returned by management service on agent creation) */\n smtpPassword: string\n\n /** How often to retry failed JMAP connection (ms, default: 5000) */\n reconnectInterval?: number\n\n /** Whether to reject unauthorized TLS certificates (default: true).\n * Set to false only for development with self-signed certificates. */\n rejectUnauthorized?: boolean\n}\n\n// =====================================================\n// Options for sending emails\n// =====================================================\nexport interface SendTaskOptions {\n /** Target node email */\n to: string\n title: string\n bodyText?: string\n timeoutSecs?: number\n contextLinks?: string[]\n dispatchContext?: Record<string, string>\n parentTaskId?: string\n /** Attachments to include with the dispatch email */\n attachments?: AampAttachment[]\n}\n\nexport interface SendResultOptions {\n /** Send to: the original from address of the dispatch email */\n to: string\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n structuredResult?: StructuredResultField[]\n /** Message-ID of the dispatch email, for In-Reply-To threading */\n inReplyTo?: string\n /** Attachments to include with the result email */\n attachments?: AampAttachment[]\n}\n\nexport interface SendHelpOptions {\n /** Send to: the original from address of the dispatch email */\n to: string\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions: string[]\n /** Message-ID of the dispatch email, for In-Reply-To threading */\n inReplyTo?: string\n /** Attachments to include with the help email */\n attachments?: AampAttachment[]\n}\n\n// =====================================================\n// Event emitter types\n// =====================================================\nexport interface AampClientEvents {\n 'task.dispatch': (task: TaskDispatch) => void\n 'task.result': (result: TaskResult) => void\n 'task.help': (help: TaskHelp) => void\n 'task.ack': (ack: TaskAck) => void\n /** Emitted when a standard email reply (no X-AAMP headers) is received for a known thread.\n * Use inReplyTo to look up the taskId in your own store (Redis / DB). */\n 'reply': (reply: HumanReply) => void\n connected: () => void\n disconnected: (reason: string) => void\n error: (err: Error) => void\n}\n", "/**\n * AAMP Header Parser\n *\n * Parses AAMP protocol headers from email messages.\n * Works with both raw header objects and JMAP Email objects.\n *\n * Headers are case-insensitive; we normalize to lowercase for lookup.\n */\n\nimport { AAMP_HEADER, type AampMessage, type TaskDispatch, type TaskResult, type TaskHelp, type TaskAck } from './types.js'\n\ntype RawHeaders = Record<string, string | string[]>\n\nfunction decodeMimeEncodedWordSegment(segment: string): string {\n const match = /^=\\?([^?]+)\\?([bBqQ])\\?([^?]*)\\?=$/.exec(segment)\n if (!match) return segment\n\n const [, charsetRaw, encodingRaw, body] = match\n const charset = charsetRaw.toLowerCase()\n const encoding = encodingRaw.toUpperCase()\n\n try {\n if (encoding === 'B') {\n const buf = Buffer.from(body, 'base64')\n return buf.toString(charset === 'utf-8' || charset === 'utf8' ? 'utf8' : 'utf8')\n }\n\n const normalized = body\n .replace(/_/g, ' ')\n .replace(/=([0-9A-Fa-f]{2})/g, (_, hex: string) =>\n String.fromCharCode(parseInt(hex, 16)),\n )\n const bytes = Buffer.from(normalized, 'binary')\n return bytes.toString(charset === 'utf-8' || charset === 'utf8' ? 'utf8' : 'utf8')\n } catch {\n return segment\n }\n}\n\nfunction decodeMimeEncodedWords(value?: string): string {\n if (!value || !value.includes('=?')) return value ?? ''\n const collapsed = value.replace(/\\r?\\n[ \\t]+/g, ' ')\n const decoded = collapsed.replace(/=\\?[^?]+\\?[bBqQ]\\?[^?]*\\?=/g, (segment) =>\n decodeMimeEncodedWordSegment(segment),\n )\n return decoded.replace(/\\s{2,}/g, ' ').trim()\n}\n\n/**\n * Normalize a header map to lowercase keys with string values\n */\nexport function normalizeHeaders(headers: RawHeaders): Record<string, string> {\n return Object.fromEntries(\n Object.entries(headers).map(([k, v]) => [\n k.toLowerCase(),\n Array.isArray(v) ? v[0] : v,\n ]),\n )\n}\n\n/**\n * Get a header value by its X-AAMP-* name (case-insensitive)\n */\nfunction getAampHeader(\n headers: Record<string, string>,\n headerName: string,\n): string | undefined {\n return headers[headerName.toLowerCase()]\n}\n\nconst DISPATCH_CONTEXT_KEY_RE = /^[a-z0-9_-]+$/\n\nexport function parseDispatchContextHeader(value?: string): Record<string, string> | undefined {\n if (!value) return undefined\n const context: Record<string, string> = {}\n\n for (const part of value.split(';')) {\n const segment = part.trim()\n if (!segment) continue\n const eqIdx = segment.indexOf('=')\n if (eqIdx <= 0) continue\n const rawKey = segment.slice(0, eqIdx).trim()\n const rawValue = segment.slice(eqIdx + 1).trim()\n if (!DISPATCH_CONTEXT_KEY_RE.test(rawKey)) continue\n try {\n context[rawKey] = decodeURIComponent(rawValue)\n } catch {\n context[rawKey] = rawValue\n }\n }\n\n return Object.keys(context).length ? context : undefined\n}\n\nexport function serializeDispatchContextHeader(context?: Record<string, string>): string | undefined {\n if (!context) return undefined\n const parts = Object.entries(context)\n .flatMap(([key, value]) => {\n const normalizedKey = key.trim().toLowerCase()\n if (!DISPATCH_CONTEXT_KEY_RE.test(normalizedKey)) return []\n const normalizedValue = String(value ?? '').trim()\n if (!normalizedValue) return []\n return `${normalizedKey}=${encodeURIComponent(normalizedValue)}`\n })\n return parts.length ? parts.join('; ') : undefined\n}\n\nfunction decodeStructuredResult(value?: string): TaskResult['structuredResult'] | undefined {\n if (!value) return undefined\n try {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/')\n const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4))\n const decoded = Buffer.from(normalized + padding, 'base64').toString('utf-8')\n return JSON.parse(decoded) as TaskResult['structuredResult']\n } catch {\n return undefined\n }\n}\n\nfunction encodeStructuredResult(value?: TaskResult['structuredResult']): string | undefined {\n if (!value) return undefined\n const json = JSON.stringify(value)\n return Buffer.from(json, 'utf-8')\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/g, '')\n}\n\nexport interface EmailMetadata {\n from: string\n to: string\n messageId: string\n subject: string\n headers: RawHeaders\n}\n\n/**\n * Parse AAMP headers from an email's header map.\n * Returns null if this email is not an AAMP message.\n *\n * @param meta - Email metadata (from, to, messageId, subject, headers)\n */\nexport function parseAampHeaders(meta: EmailMetadata): AampMessage | null {\n const headers = normalizeHeaders(meta.headers)\n\n const intent = getAampHeader(headers, AAMP_HEADER.INTENT)\n const taskId = getAampHeader(headers, AAMP_HEADER.TASK_ID)\n\n if (!intent || !taskId) return null\n\n const from = meta.from.replace(/^<|>$/g, '')\n const to = meta.to.replace(/^<|>$/g, '')\n const decodedSubject = decodeMimeEncodedWords(meta.subject)\n\n if (intent === 'task.dispatch') {\n const timeoutStr = getAampHeader(headers, AAMP_HEADER.TIMEOUT) ?? '300'\n const contextLinksStr = getAampHeader(headers, AAMP_HEADER.CONTEXT_LINKS) ?? ''\n const dispatchContext = parseDispatchContextHeader(\n getAampHeader(headers, AAMP_HEADER.DISPATCH_CONTEXT),\n )\n\n const parentTaskId = getAampHeader(headers, AAMP_HEADER.PARENT_TASK_ID)\n\n const dispatch: TaskDispatch = {\n intent: 'task.dispatch',\n taskId,\n title: decodedSubject.replace(/^\\[AAMP Task\\]\\s*/, '').trim() || 'Untitled Task',\n timeoutSecs: parseInt(timeoutStr, 10) || 300,\n contextLinks: contextLinksStr\n ? contextLinksStr.split(',').map((s) => s.trim()).filter(Boolean)\n : [],\n ...(dispatchContext ? { dispatchContext } : {}),\n ...(parentTaskId ? { parentTaskId } : {}),\n from,\n to,\n messageId: meta.messageId,\n subject: meta.subject,\n bodyText: '', // filled in by jmap-push.ts after parsing\n }\n return dispatch\n }\n\n if (intent === 'task.result') {\n const status = (getAampHeader(headers, AAMP_HEADER.STATUS) ?? 'completed') as\n | 'completed'\n | 'rejected'\n const output = getAampHeader(headers, AAMP_HEADER.OUTPUT) ?? ''\n const errorMsg = getAampHeader(headers, AAMP_HEADER.ERROR_MSG)\n const structuredResult = decodeStructuredResult(\n getAampHeader(headers, AAMP_HEADER.STRUCTURED_RESULT),\n )\n\n const result: TaskResult = {\n intent: 'task.result',\n taskId,\n status,\n output: decodeMimeEncodedWords(output),\n errorMsg: errorMsg ? decodeMimeEncodedWords(errorMsg) : errorMsg,\n structuredResult,\n from,\n to,\n messageId: meta.messageId,\n }\n return result\n }\n\n if (intent === 'task.help') {\n const question = getAampHeader(headers, AAMP_HEADER.QUESTION) ?? ''\n const blockedReason = getAampHeader(headers, AAMP_HEADER.BLOCKED_REASON) ?? ''\n const suggestedOptionsStr = getAampHeader(headers, AAMP_HEADER.SUGGESTED_OPTIONS) ?? ''\n\n const help: TaskHelp = {\n intent: 'task.help',\n taskId,\n question: decodeMimeEncodedWords(question),\n blockedReason: decodeMimeEncodedWords(blockedReason),\n suggestedOptions: suggestedOptionsStr\n ? suggestedOptionsStr.split('|').map((s) => decodeMimeEncodedWords(s.trim())).filter(Boolean)\n : [],\n from,\n to,\n messageId: meta.messageId,\n }\n return help\n }\n\n if (intent === 'task.ack') {\n const ack: TaskAck = {\n intent: 'task.ack',\n taskId,\n from,\n to,\n messageId: meta.messageId,\n }\n return ack\n }\n\n return null\n}\n\n/**\n * Build AAMP headers for a task.dispatch email\n */\nexport function buildDispatchHeaders(params: {\n taskId: string\n /** Omit or pass undefined/null to send without a deadline */\n timeoutSecs?: number | null\n contextLinks: string[]\n dispatchContext?: Record<string, string>\n parentTaskId?: string\n}): Record<string, string> {\n const headers: Record<string, string> = {\n [AAMP_HEADER.INTENT]: 'task.dispatch',\n [AAMP_HEADER.TASK_ID]: params.taskId,\n }\n if (params.timeoutSecs != null) {\n headers[AAMP_HEADER.TIMEOUT] = String(params.timeoutSecs)\n }\n if (params.contextLinks.length > 0) {\n headers[AAMP_HEADER.CONTEXT_LINKS] = params.contextLinks.join(',')\n }\n const dispatchContext = serializeDispatchContextHeader(params.dispatchContext)\n if (dispatchContext) {\n headers[AAMP_HEADER.DISPATCH_CONTEXT] = dispatchContext\n }\n if (params.parentTaskId) {\n headers[AAMP_HEADER.PARENT_TASK_ID] = params.parentTaskId\n }\n return headers\n}\n\n/**\n * Build AAMP headers for a task.ack email\n */\nexport function buildAckHeaders(opts: { taskId: string }): Record<string, string> {\n return {\n [AAMP_HEADER.INTENT]: 'task.ack',\n [AAMP_HEADER.TASK_ID]: opts.taskId,\n }\n}\n\n/**\n * Build AAMP headers for a task.result email\n */\nexport function buildResultHeaders(params: {\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n structuredResult?: TaskResult['structuredResult']\n}): Record<string, string> {\n const headers: Record<string, string> = {\n [AAMP_HEADER.INTENT]: 'task.result',\n [AAMP_HEADER.TASK_ID]: params.taskId,\n [AAMP_HEADER.STATUS]: params.status,\n [AAMP_HEADER.OUTPUT]: params.output,\n }\n if (params.errorMsg) {\n headers[AAMP_HEADER.ERROR_MSG] = params.errorMsg\n }\n const structuredResult = encodeStructuredResult(params.structuredResult)\n if (structuredResult) {\n headers[AAMP_HEADER.STRUCTURED_RESULT] = structuredResult\n }\n return headers\n}\n\n/**\n * Build AAMP headers for a task.help email\n */\nexport function buildHelpHeaders(params: {\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions: string[]\n}): Record<string, string> {\n return {\n [AAMP_HEADER.INTENT]: 'task.help',\n [AAMP_HEADER.TASK_ID]: params.taskId,\n [AAMP_HEADER.QUESTION]: params.question,\n [AAMP_HEADER.BLOCKED_REASON]: params.blockedReason,\n [AAMP_HEADER.SUGGESTED_OPTIONS]: params.suggestedOptions.join('|'),\n }\n}\n", "type Listener = (...args: unknown[]) => void\ntype EventListener<Events, K extends keyof Events> =\n Extract<Events[K], (...args: any[]) => void>\ntype EventArgs<Events, K extends keyof Events> =\n EventListener<Events, K> extends (...args: infer A) => void ? A : never\n\nexport class TinyEmitter<Events extends object> {\n private readonly listeners = new Map<keyof Events, Set<Listener>>()\n private readonly onceWrappers = new WeakMap<Listener, Listener>()\n\n on<K extends keyof Events>(event: K, listener: EventListener<Events, K>): this {\n const bucket = this.listeners.get(event) ?? new Set<Listener>()\n bucket.add(listener as Listener)\n this.listeners.set(event, bucket)\n return this\n }\n\n once<K extends keyof Events>(event: K, listener: EventListener<Events, K>): this {\n const wrapped: Listener = (...args: unknown[]) => {\n this.off(event, listener)\n ;(listener as Listener)(...args)\n }\n this.onceWrappers.set(listener as Listener, wrapped)\n return this.on(event, wrapped as EventListener<Events, K>)\n }\n\n off<K extends keyof Events>(event: K, listener: EventListener<Events, K>): this {\n const bucket = this.listeners.get(event)\n if (!bucket) return this\n\n const original = listener as Listener\n const wrapped = this.onceWrappers.get(original)\n bucket.delete(wrapped ?? original)\n if (wrapped) this.onceWrappers.delete(original)\n if (bucket.size === 0) this.listeners.delete(event)\n return this\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: EventArgs<Events, K>): boolean {\n const bucket = this.listeners.get(event)\n if (!bucket || bucket.size === 0) return false\n\n for (const listener of [...bucket]) {\n listener(...args)\n }\n return true\n }\n}\n", "/**\n * SMTP Sender\n *\n * Sends AAMP protocol emails via SMTP (Stalwart submission port 587).\n */\n\nimport { createTransport, type Transporter } from 'nodemailer'\nimport { randomUUID } from 'crypto'\n\n/** Strip CR/LF to prevent email header injection */\nconst sanitize = (s: string) => s.replace(/[\\r\\n]/g, ' ').trim()\nimport { buildDispatchHeaders, buildResultHeaders, buildHelpHeaders, buildAckHeaders } from './parser.js'\nimport type {\n SendTaskOptions,\n SendResultOptions,\n SendHelpOptions,\n} from './types.js'\n\nexport interface SmtpConfig {\n host: string\n port: number\n user: string\n password: string\n httpBaseUrl?: string\n authToken?: string\n secure?: boolean\n /** Whether to reject unauthorized TLS certificates (default: true) */\n rejectUnauthorized?: boolean\n}\n\nexport class SmtpSender {\n private transport: Transporter\n\n constructor(private readonly config: SmtpConfig) {\n this.transport = createTransport({\n host: config.host,\n port: config.port,\n secure: config.secure ?? false,\n auth: {\n user: config.user,\n pass: config.password,\n },\n tls: {\n rejectUnauthorized: config.rejectUnauthorized ?? true,\n },\n })\n }\n\n private senderDomain(): string {\n return this.config.user.split('@')[1]?.toLowerCase() ?? ''\n }\n\n private recipientDomain(email: string): string {\n return email.split('@')[1]?.toLowerCase() ?? ''\n }\n\n private shouldUseHttpFallback(to: string): boolean {\n return Boolean(\n this.config.httpBaseUrl\n && this.config.authToken\n && this.senderDomain()\n && this.senderDomain() === this.recipientDomain(to),\n )\n }\n\n private async sendViaHttp(opts: {\n to: string\n subject: string\n text: string\n aampHeaders: Record<string, string>\n attachments?: Array<{ filename: string; contentType: string; content: Buffer | string }>\n }): Promise<{ messageId?: string }> {\n const base = this.config.httpBaseUrl?.replace(/\\/$/, '')\n if (!base || !this.config.authToken) {\n throw new Error('HTTP send fallback is not configured')\n }\n\n const res = await fetch(`${base}/api/send`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${this.config.authToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n to: opts.to,\n subject: opts.subject,\n text: opts.text,\n aampHeaders: opts.aampHeaders,\n attachments: opts.attachments?.map((a) => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? a.content : a.content.toString('base64'),\n })),\n }),\n })\n\n const data = await res.json().catch(() => ({})) as { details?: string; messageId?: string }\n if (!res.ok) {\n throw new Error(data.details || `HTTP send failed: ${res.status}`)\n }\n return { messageId: data.messageId }\n }\n\n /**\n * Send a task.dispatch email.\n * Returns both the generated taskId and the SMTP Message-ID so callers can\n * store a reverse-index (messageId \u2192 taskId) for In-Reply-To thread routing.\n */\n async sendTask(opts: SendTaskOptions): Promise<{ taskId: string; messageId: string }> {\n const taskId = randomUUID()\n const aampHeaders = buildDispatchHeaders({\n taskId,\n timeoutSecs: opts.timeoutSecs,\n contextLinks: opts.contextLinks ?? [],\n parentTaskId: opts.parentTaskId,\n })\n\n const sendMailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP Task] ${sanitize(opts.title)}`,\n text: [\n `Task: ${opts.title}`,\n `Task ID: ${taskId}`,\n opts.timeoutSecs ? `Deadline: ${opts.timeoutSecs}s` : `Deadline: none`,\n opts.contextLinks?.length\n ? `Context:\\n${opts.contextLinks.map((l) => ` ${l}`).join('\\n')}`\n : '',\n opts.bodyText ?? '',\n ``,\n `--- This email was sent by AAMP. Reply directly to submit your result. ---`,\n ]\n .filter(Boolean)\n .join('\\n'),\n headers: aampHeaders,\n }\n\n if (opts.attachments?.length) {\n sendMailOpts.attachments = opts.attachments.map(a => ({\n filename: a.filename,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n contentType: a.contentType,\n }))\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n const info = await this.sendViaHttp({\n to: opts.to,\n subject: sendMailOpts.subject as string,\n text: sendMailOpts.text as string,\n aampHeaders,\n attachments: opts.attachments?.map(a => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n })),\n })\n return { taskId, messageId: info.messageId ?? '' }\n }\n\n const info = await this.transport.sendMail(sendMailOpts)\n\n return { taskId, messageId: info.messageId ?? '' }\n }\n\n /**\n * Send a task.result email back to the dispatcher\n */\n async sendResult(opts: SendResultOptions): Promise<void> {\n const aampHeaders = buildResultHeaders({\n taskId: opts.taskId,\n status: opts.status,\n output: opts.output,\n errorMsg: opts.errorMsg,\n structuredResult: opts.structuredResult,\n })\n\n const mailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP Result] Task ${opts.taskId} \u2014 ${opts.status}`,\n text: [\n `AAMP Task Result`,\n ``,\n `Task ID: ${opts.taskId}`,\n `Status: ${opts.status}`,\n ``,\n `Output:`,\n opts.output,\n opts.errorMsg ? `\\nError: ${opts.errorMsg}` : '',\n ]\n .filter((s) => s !== '')\n .join('\\n'),\n headers: aampHeaders,\n }\n if (opts.inReplyTo) {\n mailOpts.inReplyTo = opts.inReplyTo\n mailOpts.references = opts.inReplyTo\n }\n if (opts.attachments?.length) {\n mailOpts.attachments = opts.attachments.map(a => ({\n filename: a.filename,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n contentType: a.contentType,\n }))\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n await this.sendViaHttp({\n to: opts.to,\n subject: mailOpts.subject as string,\n text: mailOpts.text as string,\n aampHeaders,\n attachments: opts.attachments?.map(a => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n })),\n })\n return\n }\n await this.transport.sendMail(mailOpts)\n }\n\n /**\n * Send a task.help email when the agent is blocked\n */\n async sendHelp(opts: SendHelpOptions): Promise<void> {\n const aampHeaders = buildHelpHeaders({\n taskId: opts.taskId,\n question: opts.question,\n blockedReason: opts.blockedReason,\n suggestedOptions: opts.suggestedOptions,\n })\n\n const helpMailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP Help] Task ${opts.taskId} needs assistance`,\n text: [\n `AAMP Task Help Request`,\n ``,\n `Task ID: ${opts.taskId}`,\n ``,\n `Question: ${opts.question}`,\n ``,\n `Blocked reason: ${opts.blockedReason}`,\n ``,\n opts.suggestedOptions.length\n ? `Suggested options:\\n${opts.suggestedOptions.map((o, i) => ` ${i + 1}. ${o}`).join('\\n')}`\n : '',\n ]\n .filter(Boolean)\n .join('\\n'),\n headers: aampHeaders,\n }\n if (opts.inReplyTo) {\n helpMailOpts.inReplyTo = opts.inReplyTo\n helpMailOpts.references = opts.inReplyTo\n }\n if (opts.attachments?.length) {\n helpMailOpts.attachments = opts.attachments.map(a => ({\n filename: a.filename,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n contentType: a.contentType,\n }))\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n await this.sendViaHttp({\n to: opts.to,\n subject: helpMailOpts.subject as string,\n text: helpMailOpts.text as string,\n aampHeaders,\n attachments: opts.attachments?.map(a => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n })),\n })\n return\n }\n await this.transport.sendMail(helpMailOpts)\n }\n\n /**\n * Send a task.ack email to confirm receipt of a dispatch\n */\n async sendAck(opts: { to: string; taskId: string; inReplyTo?: string }): Promise<void> {\n const aampHeaders = buildAckHeaders({ taskId: opts.taskId })\n const mailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP ACK] Task ${opts.taskId}`,\n text: '',\n headers: aampHeaders,\n }\n if (opts.inReplyTo) {\n mailOpts.inReplyTo = opts.inReplyTo\n mailOpts.references = opts.inReplyTo\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n await this.sendViaHttp({\n to: opts.to,\n subject: mailOpts.subject as string,\n text: mailOpts.text as string,\n aampHeaders,\n })\n return\n }\n await this.transport.sendMail(mailOpts)\n }\n\n /**\n * Verify SMTP connection\n */\n async verify(): Promise<boolean> {\n try {\n await this.transport.verify()\n return true\n } catch {\n return false\n }\n }\n\n close(): void {\n this.transport.close()\n }\n}\n", "/**\n * AampClient \u2014 Main SDK entry point\n *\n * Combines JMAP WebSocket Push (receive) + SMTP (send) into a single client.\n *\n * Usage:\n *\n * ```typescript\n * const client = new AampClient({\n * email: 'codereviewer-abc@aamp.example.com',\n * jmapToken: '<base64-token>',\n * jmapUrl: 'http://localhost:8080',\n * smtpHost: 'localhost',\n * smtpPort: 587,\n * smtpPassword: 'agent-smtp-password',\n * })\n *\n * // Listen for incoming tasks\n * client.on('task.dispatch', async (task) => {\n * const result = await doWork(task)\n * await client.sendResult({\n * to: task.from,\n * taskId: task.taskId,\n * status: 'completed',\n * output: result,\n * })\n * })\n *\n * await client.connect()\n * ```\n */\n\nimport { JmapPushClient } from './jmap-push.js'\nimport { SmtpSender } from './smtp-sender.js'\nimport { TinyEmitter } from './tiny-emitter.js'\nimport type {\n AampClientConfig,\n AampClientEvents,\n TaskDispatch,\n TaskResult,\n TaskHelp,\n TaskAck,\n HumanReply,\n SendTaskOptions,\n SendResultOptions,\n SendHelpOptions,\n} from './types.js'\n\nexport class AampClient extends TinyEmitter<AampClientEvents> {\n private jmapClient: JmapPushClient\n private smtpSender: SmtpSender\n private readonly config: AampClientConfig\n\n constructor(config: AampClientConfig) {\n super()\n this.config = config\n\n // Decode JMAP token (format: base64(email:password))\n let password: string\n try {\n const decoded = Buffer.from(config.jmapToken, 'base64').toString('utf-8')\n const colonIdx = decoded.indexOf(':')\n if (colonIdx < 0) throw new Error('Invalid jmapToken format: expected base64(email:password)')\n password = decoded.slice(colonIdx + 1)\n if (!password) throw new Error('Invalid jmapToken: empty password')\n } catch (err) {\n if (err instanceof Error && err.message.startsWith('Invalid jmapToken')) throw err\n throw new Error(`Failed to decode jmapToken: ${(err as Error).message}`)\n }\n\n this.jmapClient = new JmapPushClient({\n email: config.email,\n password: password ?? config.smtpPassword,\n jmapUrl: config.jmapUrl,\n reconnectInterval: config.reconnectInterval ?? 5000,\n rejectUnauthorized: config.rejectUnauthorized,\n })\n\n this.smtpSender = new SmtpSender({\n host: config.smtpHost,\n port: config.smtpPort ?? 587,\n user: config.email,\n password: config.smtpPassword,\n httpBaseUrl: config.httpSendBaseUrl ?? config.jmapUrl,\n authToken: config.jmapToken,\n rejectUnauthorized: config.rejectUnauthorized,\n })\n\n // Forward JMAP events to this emitter\n this.jmapClient.on('task.dispatch', (task: TaskDispatch) => {\n this.emit('task.dispatch', task)\n })\n\n this.jmapClient.on('task.result', (result: TaskResult) => {\n this.emit('task.result', result)\n })\n\n this.jmapClient.on('task.help', (help: TaskHelp) => {\n this.emit('task.help', help)\n })\n\n this.jmapClient.on('task.ack', (ack: TaskAck) => {\n this.emit('task.ack', ack)\n })\n\n // Auto-ACK: when a task.dispatch is received, automatically send an ACK back\n this.jmapClient.on('_autoAck', async ({ to, taskId, messageId }: { to: string; taskId: string; messageId: string }) => {\n try {\n await this.smtpSender.sendAck({ to, taskId, inReplyTo: messageId })\n } catch (err) {\n console.warn(`[AAMP] Failed to send ACK for task ${taskId}: ${(err as Error).message}`)\n }\n })\n\n this.jmapClient.on('reply', (reply: HumanReply) => {\n this.emit('reply', reply)\n })\n\n this.jmapClient.on('connected', () => {\n this.emit('connected')\n })\n\n this.jmapClient.on('disconnected', (reason: string) => {\n this.emit('disconnected', reason)\n })\n\n this.jmapClient.on('error', (err: Error) => {\n this.emit('error', err)\n })\n }\n\n // =====================================================\n // Lifecycle\n // =====================================================\n\n /**\n * Connect to JMAP and start listening for tasks\n */\n async connect(): Promise<void> {\n await this.jmapClient.start()\n }\n\n /**\n * Disconnect and clean up\n */\n disconnect(): void {\n this.jmapClient.stop()\n this.smtpSender.close()\n }\n\n /**\n * Returns true if the JMAP connection is active\n */\n isConnected(): boolean {\n return this.jmapClient.isConnected()\n }\n\n isUsingPollingFallback(): boolean {\n return this.jmapClient.isUsingPollingFallback()\n }\n\n // =====================================================\n // Sending\n // =====================================================\n\n /**\n * Send a task.dispatch email to an agent.\n * Returns the generated taskId and the SMTP Message-ID.\n * Store messageId \u2192 taskId in Redis/DB to support In-Reply-To thread routing\n * for human replies that arrive without X-AAMP headers.\n */\n async sendTask(opts: SendTaskOptions): Promise<{ taskId: string; messageId: string }> {\n return this.smtpSender.sendTask(opts)\n }\n\n /**\n * Send a task.result email (agent \u2192 system/dispatcher)\n */\n async sendResult(opts: SendResultOptions): Promise<void> {\n return this.smtpSender.sendResult(opts)\n }\n\n /**\n * Send a task.help email when the agent needs human assistance\n */\n async sendHelp(opts: SendHelpOptions): Promise<void> {\n return this.smtpSender.sendHelp(opts)\n }\n\n /**\n * Download a blob (attachment) by its JMAP blobId.\n * Use this to retrieve attachment content from received TaskDispatch or TaskResult messages.\n * Returns the raw binary content as a Buffer.\n */\n async downloadBlob(blobId: string, filename?: string): Promise<Buffer> {\n return this.jmapClient.downloadBlob(blobId, filename)\n }\n\n /**\n * Reconcile recent mailbox contents via JMAP HTTP to catch messages missed by\n * a flaky WebSocket path. Safe to call periodically; duplicate processing is\n * suppressed by the JMAP push client.\n */\n async reconcileRecentEmails(limit?: number): Promise<number> {\n return this.jmapClient.reconcileRecentEmails(limit)\n }\n\n /**\n * Verify SMTP connectivity\n */\n async verifySmtp(): Promise<boolean> {\n return this.smtpSender.verify()\n }\n\n get email(): string {\n return this.config.email\n }\n}\n", "import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { homedir } from 'node:os'\n\nexport interface Identity {\n email: string\n jmapToken: string\n smtpPassword: string\n}\n\nexport function defaultCredentialsPath(): string {\n return join(homedir(), '.openclaw', 'extensions', 'aamp-openclaw-plugin', '.credentials.json')\n}\n\nexport function loadCachedIdentity(file?: string): Identity | null {\n const resolved = file ?? defaultCredentialsPath()\n if (!existsSync(resolved)) return null\n try {\n const parsed = JSON.parse(readFileSync(resolved, 'utf-8')) as Partial<Identity>\n if (!parsed.email || !parsed.jmapToken || !parsed.smtpPassword) return null\n return parsed as Identity\n } catch {\n return null\n }\n}\n\nexport function saveCachedIdentity(identity: Identity, file?: string): void {\n const resolved = file ?? defaultCredentialsPath()\n mkdirSync(dirname(resolved), { recursive: true })\n writeFileSync(resolved, JSON.stringify(identity, null, 2), 'utf-8')\n}\n\nexport function ensureDir(dir: string): void {\n mkdirSync(dir, { recursive: true })\n}\n\nexport function readBinaryFile(path: string): Buffer {\n return readFileSync(path)\n}\n\nexport function writeBinaryFile(path: string, content: Uint8Array | Buffer): void {\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n}\n", "/**\n * @aamp/openclaw-plugin\n *\n * OpenClaw plugin that gives the agent an AAMP mailbox identity and lets it\n * receive, process, and reply to AAMP tasks \u2014 entirely through standard email.\n *\n * How it works:\n * 1. Plugin resolves or auto-registers an AAMP mailbox identity on startup.\n * 2. Credentials are cached to a local file so the same mailbox is reused\n * across gateway restarts (no re-registration needed).\n * 3. Background JMAP WebSocket Push receives incoming task.dispatch emails.\n * 4. Incoming tasks are stored in an in-memory pending-task queue.\n * 5. before_prompt_build injects the oldest pending task into the LLM's\n * system context so the agent sees it and acts without user prompting.\n * 6. The agent calls aamp_send_result or aamp_send_help to reply.\n *\n * OpenClaw config (openclaw.json):\n *\n * \"plugins\": {\n * \"entries\": {\n * \"aamp\": {\n * \"enabled\": true,\n * \"config\": {\n * \"aampHost\": \"https://meshmail.ai\",\n * \"slug\": \"openclaw-agent\",\n * \"credentialsFile\": \"/absolute/path/to/.aamp-credentials.json\"\n * }\n * }\n * }\n * }\n *\n * Install:\n * openclaw plugins install ./packages/openclaw-plugin\n */\n\nimport { AampClient } from '../../sdk/src/index.ts'\nimport type {\n TaskDispatch,\n TaskResult,\n TaskHelp,\n AampAttachment,\n ReceivedAttachment,\n} from '../../sdk/src/types.ts'\nimport {\n defaultCredentialsPath,\n ensureDir,\n loadCachedIdentity,\n readBinaryFile,\n saveCachedIdentity,\n writeBinaryFile,\n type Identity,\n} from './file-store.js'\n\n// \u2500\u2500\u2500 Shared runtime state (single instance per plugin lifetime) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface PendingTask {\n taskId: string\n from: string\n title: string\n bodyText: string\n contextLinks: string[]\n timeoutSecs: number\n messageId: string\n receivedAt: string // ISO-8601\n}\n\ninterface PluginConfig {\n /** e.g. \"meshmail.ai\" \u2014 all URLs are derived from this */\n aampHost: string\n slug?: string\n /** Absolute path to cache AAMP credentials. Default: ~/.openclaw/extensions/aamp-openclaw-plugin/.credentials.json */\n credentialsFile?: string\n senderPolicies?: SenderPolicy[]\n}\n\ninterface SenderPolicy {\n sender: string\n dispatchContextRules?: Record<string, string[]>\n}\n\nfunction matchSenderPolicy(\n task: TaskDispatch,\n senderPolicies: SenderPolicy[] | undefined,\n): { allowed: boolean; reason?: string } {\n if (!senderPolicies?.length) return { allowed: true }\n\n const sender = task.from.toLowerCase()\n const policy = senderPolicies.find((item) => item.sender.trim().toLowerCase() === sender)\n if (!policy) {\n return { allowed: false, reason: `sender ${task.from} is not allowed by senderPolicies` }\n }\n\n const rules = policy.dispatchContextRules\n if (!rules || Object.keys(rules).length === 0) {\n return { allowed: true }\n }\n\n const context = task.dispatchContext ?? {}\n const effectiveRules = Object.entries(rules)\n .map(([key, allowedValues]) => [\n key,\n (allowedValues ?? []).map((value) => value.trim()).filter(Boolean),\n ] as const)\n .filter(([, allowedValues]) => allowedValues.length > 0)\n\n if (effectiveRules.length === 0) {\n return { allowed: true }\n }\n\n for (const [key, allowedValues] of effectiveRules) {\n const contextValue = context[key]\n if (!contextValue) {\n return { allowed: false, reason: `dispatchContext missing required key \"${key}\"` }\n }\n if (!allowedValues.includes(contextValue)) {\n return { allowed: false, reason: `dispatchContext ${key}=${contextValue} is not allowed` }\n }\n }\n\n return { allowed: true }\n}\n\ntype StructuredResultFieldInput = {\n fieldKey: string\n fieldTypeKey: string\n fieldAlias?: string\n value?: unknown\n index?: string\n attachmentFilenames?: string[]\n}\n\n/** Normalise aampHost to a base URL with scheme and no trailing slash */\nfunction baseUrl(aampHost: string): string {\n if (aampHost.startsWith('http://') || aampHost.startsWith('https://')) {\n return aampHost.replace(/\\/$/, '')\n }\n return `https://${aampHost}`\n}\n\nconst pendingTasks = new Map<string, PendingTask>()\n// Tracks sub-tasks dispatched TO other agents \u2014 waiting for their result/help replies\nconst dispatchedSubtasks = new Map<string, { to: string; title: string; dispatchedAt: string; parentTaskId?: string }>()\n// Tracks notification keys that have been shown to LLM (auto-cleaned on next prompt build)\nconst shownNotifications = new Set<string>()\n// Pending synchronous dispatch waiters \u2014 resolve callback keyed by sub-task ID.\n// When aamp_dispatch_task sends a sub-task, it parks a Promise here and waits.\n// When task.result/help arrives for that sub-task ID, the waiter is resolved\n// directly, keeping the LLM awake with full context (no heartbeat needed).\nconst waitingDispatches = new Map<string, (reply: { type: 'result' | 'help'; data: unknown }) => void>()\nlet aampClient: AampClient | null = null\nlet agentEmail = ''\nlet lastConnectionError = ''\nlet lastDisconnectReason = ''\nlet lastTransportMode: 'disconnected' | 'websocket' | 'polling' = 'disconnected'\nlet lastLoggedTransportMode: 'disconnected' | 'websocket' | 'polling' = 'disconnected'\nlet reconcileTimer: NodeJS.Timeout | null = null\nlet transportMonitorTimer: NodeJS.Timeout | null = null\n// Tracks the most recently seen session key so task.dispatch can wake the right session.\n// Default 'agent:main:main' is the standard OpenClaw single-agent session key.\nlet currentSessionKey = 'agent:main:main'\n// Channel runtime \u2014 captured from channel adapter's startAccount for instant dispatch.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet channelRuntime: any = null\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet channelCfg: any = null\n\nfunction logTransportState(\n api: { logger: { info: (msg: string) => void; warn: (msg: string) => void } },\n mode: 'websocket' | 'polling',\n email: string,\n previousMode: 'disconnected' | 'websocket' | 'polling',\n): void {\n if (mode === previousMode) return\n\n if (mode === 'polling') {\n api.logger.info(`[AAMP] Connected (polling fallback active) \u2014 listening as ${email}`)\n return\n }\n\n if (previousMode === 'polling') {\n api.logger.info(`[AAMP] WebSocket restored \u2014 listening as ${email}`)\n return\n }\n\n api.logger.info(`[AAMP] Connected \u2014 listening as ${email}`)\n}\n\n// \u2500\u2500\u2500 Identity helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface Identity {\n email: string\n jmapToken: string\n smtpPassword: string\n}\n\n/**\n * Register a new AAMP node via the management service.\n *\n * Always creates a NEW mailbox (always returns 201). The slug is just a\n * human-readable prefix; a random hex suffix makes the email unique.\n * Callers should only call this once and persist the returned credentials.\n */\nasync function registerNode(cfg: PluginConfig): Promise<Identity> {\n const slug = (cfg.slug ?? 'openclaw-agent')\n .toLowerCase()\n .replace(/[\\s_]+/g, '-')\n .replace(/[^a-z0-9-]/g, '')\n\n const base = baseUrl(cfg.aampHost)\n\n // Step 1: Self-register \u2192 get one-time registration code\n const res = await fetch(`${base}/api/nodes/self-register`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ slug, description: 'OpenClaw AAMP agent node' }),\n })\n\n if (!res.ok) {\n const err = (await res.json().catch(() => ({}))) as { error?: string }\n throw new Error(`AAMP registration failed (${res.status}): ${err.error ?? res.statusText}`)\n }\n\n const regData = (await res.json()) as {\n registrationCode: string\n email: string\n }\n\n // Step 2: Exchange registration code for credentials\n const credRes = await fetch(\n `${base}/api/nodes/credentials?code=${encodeURIComponent(regData.registrationCode)}`,\n )\n\n if (!credRes.ok) {\n const err = (await credRes.json().catch(() => ({}))) as { error?: string }\n throw new Error(`AAMP credential exchange failed (${credRes.status}): ${err.error ?? credRes.statusText}`)\n }\n\n const credData = (await credRes.json()) as {\n email: string\n jmap: { token: string }\n smtp: { password: string }\n }\n\n return {\n email: credData.email,\n jmapToken: credData.jmap.token,\n smtpPassword: credData.smtp.password,\n }\n}\n\n/**\n * Resolve this agent's identity:\n * 1. Return cached credentials from disk if available.\n * 2. Otherwise register a new node and cache the result.\n */\nasync function resolveIdentity(cfg: PluginConfig): Promise<Identity> {\n const cached = loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath())\n if (cached) return cached\n\n const identity = await registerNode(cfg)\n saveCachedIdentity(identity, cfg.credentialsFile ?? defaultCredentialsPath())\n return identity\n}\n\n// \u2500\u2500\u2500 Plugin definition \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default {\n id: 'aamp-openclaw-plugin',\n name: 'AAMP Agent Mail Protocol',\n\n configSchema: {\n type: 'object',\n properties: {\n aampHost: {\n type: 'string',\n description: 'AAMP service host, e.g. https://meshmail.ai',\n },\n slug: {\n type: 'string',\n default: 'openclaw-agent',\n description: 'Agent name prefix used in the mailbox address',\n },\n credentialsFile: {\n type: 'string',\n description:\n 'Absolute path to cache AAMP credentials between gateway restarts. ' +\n 'Default: ~/.openclaw/extensions/aamp-openclaw-plugin/.credentials.json. ' +\n 'Delete this file to force re-registration with a new mailbox.',\n },\n senderPolicies: {\n type: 'array',\n description:\n 'Per-sender authorization policies. Each sender can optionally require specific ' +\n 'X-AAMP-Dispatch-Context key/value pairs before a task is accepted.',\n items: {\n type: 'object',\n required: ['sender'],\n properties: {\n sender: {\n type: 'string',\n description: 'Dispatch sender email address (case-insensitive exact match).',\n },\n dispatchContextRules: {\n type: 'object',\n description:\n 'Optional exact-match rules over X-AAMP-Dispatch-Context. ' +\n 'All listed keys must be present and their values must match one of the configured entries.',\n additionalProperties: {\n type: 'array',\n items: { type: 'string' },\n },\n },\n },\n },\n },\n },\n },\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n register(api: any) {\n // api.pluginConfig = the config block under plugins.entries[\"aamp-openclaw-plugin\"].config in openclaw.json\n // api.config = the full global OpenClaw config (NOT our plugin's config)\n const cfg = (api.pluginConfig ?? {}) as PluginConfig\n\n // \u2500\u2500 Register lightweight channel adapter to capture channelRuntime \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // We register as a channel SOLELY to get access to channelRuntime, which provides\n // dispatchReplyWithBufferedBlockDispatcher for instant LLM dispatch (bypassing\n // heartbeat's global running-mutex + requests-in-flight ~60s delay).\n // JMAP connection is managed by registerService, NOT startAccount.\n api.registerChannel({\n id: 'aamp',\n meta: { label: 'AAMP' },\n capabilities: { chatTypes: ['dm'] },\n config: {\n listAccountIds: () => cfg.aampHost ? ['default'] : [],\n resolveAccount: () => ({ aampHost: cfg.aampHost }),\n isEnabled: () => !!cfg.aampHost,\n isConfigured: () => !!loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath()),\n },\n gateway: {\n startAccount: async (ctx: { channelRuntime?: unknown; cfg?: unknown; abortSignal?: AbortSignal }) => {\n // Capture channelRuntime for use by sub-task notification dispatch\n channelRuntime = ctx.channelRuntime ?? null\n channelCfg = ctx.cfg ?? null\n api.logger.info(`[AAMP] Channel adapter started \u2014 channelRuntime ${channelRuntime ? 'available' : 'NOT available'}`)\n\n // Keep alive until abort \u2014 JMAP connection is managed by registerService\n await new Promise<void>((resolve) => {\n ctx.abortSignal?.addEventListener('abort', () => resolve())\n })\n channelRuntime = null\n channelCfg = null\n },\n stopAccount: async () => {\n channelRuntime = null\n channelCfg = null\n },\n },\n })\n\n function triggerHeartbeatWake(sessionKey: string, label: string): void {\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey })\n api.logger.info(`[AAMP] Heartbeat triggered for ${label} via session ${sessionKey}`)\n } catch (err) {\n api.logger.warn(`[AAMP] Could not trigger heartbeat for ${label}: ${(err as Error).message}`)\n }\n }\n\n function wakeAgentForPendingTask(task: PendingTask): void {\n const fallback = () => triggerHeartbeatWake(currentSessionKey, `task ${task.taskId}`)\n const dispatcher = channelRuntime?.reply?.dispatchReplyWithBufferedBlockDispatcher\n\n api.logger.info(\n `[AAMP] Wake requested for task ${task.taskId} \u2014 channelRuntime=${channelRuntime ? 'yes' : 'no'} channelCfg=${channelCfg ? 'yes' : 'no'} dispatcher=${typeof dispatcher === 'function' ? 'yes' : 'no'} session=${currentSessionKey}`,\n )\n\n if (!channelRuntime || !channelCfg || typeof dispatcher !== 'function') {\n fallback()\n return\n }\n\n const prompt = [\n '## New AAMP Task',\n '',\n 'A new AAMP task just arrived.',\n 'Use the pending AAMP task in system context as the source of truth and handle it now.',\n 'Reply with aamp_send_result or aamp_send_help before responding.',\n ].join('\\n')\n\n try {\n void Promise.resolve(dispatcher({\n ctx: {\n Body: task.bodyText || task.title,\n BodyForAgent: prompt,\n From: task.from,\n To: agentEmail,\n SessionKey: `aamp:default:task:${task.taskId}`,\n AccountId: 'default',\n ChatType: 'dm',\n Provider: 'aamp',\n Surface: 'aamp',\n OriginatingChannel: 'aamp',\n OriginatingTo: task.from,\n MessageSid: task.messageId || task.taskId,\n Timestamp: Date.now(),\n SenderName: task.from,\n SenderId: task.from,\n CommandAuthorized: true,\n },\n cfg: channelCfg,\n dispatcherOptions: {\n deliver: async () => {},\n onError: (err: unknown) => {\n api.logger.error(`[AAMP] Channel dispatch error for task ${task.taskId}: ${err instanceof Error ? err.message : String(err)}`)\n },\n },\n })).then(() => {\n api.logger.info(`[AAMP] Channel dispatch triggered for task ${task.taskId}`)\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Channel dispatch failed for task ${task.taskId}: ${err.message}`)\n fallback()\n })\n } catch (err) {\n api.logger.error(`[AAMP] Channel dispatch threw synchronously for task ${task.taskId}: ${(err as Error).message}`)\n fallback()\n }\n }\n\n // \u2500\u2500 Shared connect logic (used by service auto-connect and startup recovery) \u2500\u2500\u2500\u2500\u2500\u2500\n async function doConnect(identity: { email: string; jmapToken: string; smtpPassword: string }) {\n if (reconcileTimer) {\n clearInterval(reconcileTimer)\n reconcileTimer = null\n }\n if (transportMonitorTimer) {\n clearInterval(transportMonitorTimer)\n transportMonitorTimer = null\n }\n\n agentEmail = identity.email\n lastConnectionError = ''\n lastDisconnectReason = ''\n lastTransportMode = 'disconnected'\n lastLoggedTransportMode = 'disconnected'\n api.logger.info(`[AAMP] Mailbox identity ready \u2014 ${agentEmail}`)\n\n // All traffic goes through aampHost (port 3000).\n // The management service proxies /jmap/* and /.well-known/jmap \u2192 Stalwart:8080.\n const base = baseUrl(cfg.aampHost)\n\n aampClient = new AampClient({\n email: identity.email,\n jmapToken: identity.jmapToken,\n jmapUrl: base,\n smtpHost: new URL(base).hostname,\n smtpPort: 587,\n smtpPassword: identity.smtpPassword,\n // Local/dev: management-service proxy uses plain HTTP, no TLS cert to verify.\n // Production: set to true when using wss:// with valid certs.\n rejectUnauthorized: false,\n })\n\n aampClient.on('task.dispatch', (task: TaskDispatch) => {\n api.logger.info(`[AAMP] \u2190 task.dispatch ${task.taskId} \"${task.title}\" from=${task.from}`)\n\n try {\n // \u2500\u2500 Sender policy / dispatch-context authorization \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const decision = matchSenderPolicy(task, cfg.senderPolicies)\n if (!decision.allowed) {\n api.logger.warn(`[AAMP] \u2717 rejected by senderPolicies: ${task.from} task=${task.taskId} reason=${decision.reason}`)\n void aampClient!.sendResult({\n to: task.from,\n taskId: task.taskId,\n status: 'rejected',\n output: '',\n errorMsg: decision.reason ?? `Sender ${task.from} is not allowed.`,\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Failed to send rejection for task ${task.taskId}: ${err.message}`)\n })\n return\n }\n\n pendingTasks.set(task.taskId, {\n taskId: task.taskId,\n from: task.from,\n title: task.title,\n bodyText: task.bodyText ?? '',\n contextLinks: task.contextLinks,\n timeoutSecs: task.timeoutSecs,\n messageId: task.messageId ?? '',\n receivedAt: new Date().toISOString(),\n })\n\n // Wake the agent immediately after enqueueing the task.\n // In polling fallback mode heartbeat wakes can be delayed, so prefer a direct\n // channel dispatch when channelRuntime is available and only fall back to heartbeat.\n wakeAgentForPendingTask(pendingTasks.get(task.taskId)!)\n } catch (err) {\n api.logger.error(`[AAMP] task.dispatch handler failed for ${task.taskId}: ${(err as Error).message}`)\n if (pendingTasks.has(task.taskId)) {\n triggerHeartbeatWake(currentSessionKey, `task ${task.taskId}`)\n }\n }\n })\n\n // \u2500\u2500 Sub-task result: another agent completed a task we dispatched \u2500\u2500\u2500\u2500\u2500\u2500\n aampClient.on('task.result', (result: TaskResult) => {\n api.logger.info(`[AAMP] \u2190 task.result ${result.taskId} status=${result.status} from=${result.from}`)\n\n const sub = dispatchedSubtasks.get(result.taskId)\n dispatchedSubtasks.delete(result.taskId)\n\n // \u2500\u2500 Synchronous dispatch: if aamp_dispatch_task is waiting, resolve it directly \u2500\u2500\n const waiter = waitingDispatches.get(result.taskId)\n if (waiter) {\n waitingDispatches.delete(result.taskId)\n api.logger.info(`[AAMP] Resolving sync waiter for sub-task ${result.taskId}`)\n waiter({ type: 'result', data: result })\n return // Don't go through heartbeat/channel \u2014 the LLM is already awake\n }\n\n // Pre-download attachments to local disk so the LLM can reference them\n // by local file path (instead of requiring a separate download tool call).\n const downloadedFiles: Array<{ filename: string; path: string; size: number }> = []\n const downloadPromise = (async () => {\n if (!result.attachments?.length) return\n const dir = '/tmp/aamp-files'\n ensureDir(dir)\n for (const att of result.attachments) {\n try {\n const buffer = await aampClient!.downloadBlob(att.blobId, att.filename)\n const filepath = `${dir}/${att.filename}`\n writeBinaryFile(filepath, buffer)\n downloadedFiles.push({ filename: att.filename, path: filepath, size: buffer.length })\n api.logger.info(`[AAMP] Pre-downloaded: ${att.filename} (${(buffer.length / 1024).toFixed(1)} KB) \u2192 ${filepath}`)\n } catch (dlErr) {\n api.logger.warn(`[AAMP] Pre-download failed for ${att.filename}: ${(dlErr as Error).message}`)\n }\n }\n })()\n\n downloadPromise.then(() => {\n // Build notification with pre-downloaded file paths\n const MAX_OUTPUT_CHARS = 800\n const label = result.status === 'completed' ? 'Sub-task completed' : 'Sub-task rejected'\n const rawOutput = result.output ?? ''\n const truncatedOutput = rawOutput.length > MAX_OUTPUT_CHARS\n ? rawOutput.slice(0, MAX_OUTPUT_CHARS) + `\\n\\n... [truncated, ${rawOutput.length} chars total]`\n : rawOutput\n\n let attachmentInfo = ''\n if (downloadedFiles.length > 0) {\n attachmentInfo = `\\n\\nAttachments (pre-downloaded to local disk):\\n${downloadedFiles.map(f =>\n `- ${f.filename} (${(f.size / 1024).toFixed(1)} KB) \u2192 ${f.path}`\n ).join('\\n')}\\nUse aamp_send_result with attachments: [${downloadedFiles.map(f => `{ filename: \"${f.filename}\", path: \"${f.path}\" }`).join(', ')}] to forward them.`\n } else if (result.attachments?.length) {\n const files = result.attachments.map((a: ReceivedAttachment) =>\n `${a.filename} (${(a.size / 1024).toFixed(1)} KB, blobId: ${a.blobId})`,\n )\n attachmentInfo = `\\n\\nAttachments (download failed \u2014 use aamp_download_attachment manually):\\n${files.join('\\n')}`\n }\n\n pendingTasks.set(`result:${result.taskId}`, {\n taskId: result.taskId,\n from: result.from,\n title: `${label}: ${sub?.title ?? result.taskId}`,\n bodyText: result.status === 'completed'\n ? `Agent ${result.from} completed the sub-task.\\n\\nOutput:\\n${truncatedOutput}${attachmentInfo}`\n : `Agent ${result.from} rejected the sub-task.\\n\\nReason: ${result.errorMsg ?? 'unknown'}`,\n contextLinks: [],\n timeoutSecs: 0,\n messageId: '',\n receivedAt: new Date().toISOString(),\n })\n\n // Wake LLM via channel dispatch (instant) or heartbeat (fallback)\n if (channelRuntime && channelCfg) {\n const notifyBody = pendingTasks.get(`result:${result.taskId}`)\n const actionableTasks = [...pendingTasks.entries()]\n .filter(([key]) => !key.startsWith('result:') && !key.startsWith('help:'))\n .map(([, t]) => t)\n const actionSection = actionableTasks.length > 0\n ? `\\n\\n### Action Required\\nYou MUST call aamp_send_result to complete the pending task(s):\\n${actionableTasks.map(t => `- Task ID: ${t.taskId} | From: ${t.from} | Title: \"${t.title}\"`).join('\\n')}`\n : ''\n const prompt = `## Sub-task Update\\n\\n${notifyBody?.bodyText ?? 'Sub-task completed.'}${actionSection}`\n\n channelRuntime.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: {\n Body: `Sub-task result: ${result.taskId}`,\n BodyForAgent: prompt,\n From: result.from,\n To: agentEmail,\n SessionKey: `aamp:default:${result.from}`,\n AccountId: 'default',\n ChatType: 'dm',\n Provider: 'aamp',\n Surface: 'aamp',\n OriginatingChannel: 'aamp',\n OriginatingTo: result.from,\n MessageSid: result.taskId,\n Timestamp: Date.now(),\n SenderName: result.from,\n SenderId: result.from,\n CommandAuthorized: true,\n },\n cfg: channelCfg,\n dispatcherOptions: {\n deliver: async () => {},\n onError: (err: unknown) => {\n api.logger.error(`[AAMP] Channel dispatch error: ${err instanceof Error ? err.message : String(err)}`)\n },\n },\n }).then(() => {\n api.logger.info(`[AAMP] Channel dispatch completed for sub-task result ${result.taskId}`)\n pendingTasks.delete(`result:${result.taskId}`)\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Channel dispatch failed: ${err.message}`)\n })\n } else {\n const notifySessionKey = `agent:main:aamp-notify-${Date.now()}`\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: notifySessionKey })\n api.logger.info(`[AAMP] Heartbeat for sub-task result ${result.taskId}`)\n } catch (err) {\n api.logger.warn(`[AAMP] Heartbeat for sub-task result failed: ${(err as Error).message}`)\n }\n }\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Sub-task result processing failed: ${err.message}`)\n })\n })\n\n // \u2500\u2500 Sub-task help: another agent asks for clarification \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n aampClient.on('task.help', (help: TaskHelp) => {\n api.logger.info(`[AAMP] \u2190 task.help ${help.taskId} question=\"${help.question}\" from=${help.from}`)\n\n // \u2500\u2500 Synchronous dispatch: if aamp_dispatch_task is waiting, resolve it directly \u2500\u2500\n const waiter = waitingDispatches.get(help.taskId)\n if (waiter) {\n waitingDispatches.delete(help.taskId)\n api.logger.info(`[AAMP] Resolving sync waiter for sub-task help ${help.taskId}`)\n waiter({ type: 'help', data: help })\n return\n }\n\n const sub = dispatchedSubtasks.get(help.taskId)\n\n pendingTasks.set(`help:${help.taskId}`, {\n taskId: help.taskId,\n from: help.from,\n title: `Sub-task needs help: ${sub?.title ?? help.taskId}`,\n bodyText: `Agent ${help.from} is asking for help on the sub-task.\\n\\nQuestion: ${help.question}\\nBlocked reason: ${help.blockedReason}${help.suggestedOptions?.length ? `\\nSuggested options: ${help.suggestedOptions.join(', ')}` : ''}`,\n contextLinks: [],\n timeoutSecs: 0,\n messageId: '',\n receivedAt: new Date().toISOString(),\n })\n\n if (channelRuntime && channelCfg) {\n const notifyBody = pendingTasks.get(`help:${help.taskId}`)\n const prompt = `## Sub-task Help Request\\n\\n${notifyBody?.bodyText ?? help.question}`\n\n channelRuntime.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: {\n Body: `Sub-task help: ${help.taskId}`,\n BodyForAgent: prompt,\n From: help.from,\n To: agentEmail,\n SessionKey: `aamp:default:${help.from}`,\n AccountId: 'default',\n ChatType: 'dm',\n Provider: 'aamp',\n Surface: 'aamp',\n OriginatingChannel: 'aamp',\n OriginatingTo: help.from,\n MessageSid: help.taskId,\n Timestamp: Date.now(),\n SenderName: help.from,\n SenderId: help.from,\n CommandAuthorized: true,\n },\n cfg: channelCfg,\n dispatcherOptions: {\n deliver: async () => {},\n onError: (err: unknown) => {\n api.logger.error(`[AAMP] Channel dispatch error (help): ${err instanceof Error ? err.message : String(err)}`)\n },\n },\n }).then(() => {\n pendingTasks.delete(`help:${help.taskId}`)\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Channel dispatch failed for help: ${err.message}`)\n })\n } else {\n const helpSessionKey = `agent:main:aamp-notify-${Date.now()}`\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: helpSessionKey })\n api.logger.info(`[AAMP] Heartbeat fallback for sub-task help ${help.taskId}`)\n } catch (err) {\n api.logger.warn(`[AAMP] Heartbeat for sub-task help failed: ${(err as Error).message}`)\n }\n }\n })\n\n aampClient.on('connected', () => {\n lastConnectionError = ''\n lastDisconnectReason = ''\n const mode = aampClient?.isUsingPollingFallback() ? 'polling' : 'websocket'\n logTransportState(api, mode, agentEmail, lastLoggedTransportMode)\n lastTransportMode = mode\n lastLoggedTransportMode = mode\n })\n\n aampClient.on('disconnected', (reason: string) => {\n lastDisconnectReason = reason\n if (lastTransportMode !== 'disconnected') {\n api.logger.warn(`[AAMP] Disconnected: ${reason} (will auto-reconnect)`)\n lastTransportMode = 'disconnected'\n lastLoggedTransportMode = 'disconnected'\n }\n })\n\n aampClient.on('error', (err: Error) => {\n lastConnectionError = err.message\n if (err.message.startsWith('JMAP WebSocket unavailable, falling back to polling:')) {\n if (lastTransportMode !== 'polling') {\n logTransportState(api, 'polling', agentEmail, lastLoggedTransportMode)\n lastTransportMode = 'polling'\n lastLoggedTransportMode = 'polling'\n }\n return\n }\n api.logger.error(`[AAMP] ${err.message}`)\n })\n\n await aampClient.connect()\n\n api.logger.info(\n `[AAMP] Transport after connect \u2014 ${aampClient.isUsingPollingFallback() ? 'polling fallback' : 'websocket'} as ${agentEmail}`,\n )\n\n if (aampClient.isConnected() && lastTransportMode === 'disconnected') {\n if (aampClient.isUsingPollingFallback()) {\n logTransportState(api, 'polling', agentEmail, lastLoggedTransportMode)\n lastTransportMode = 'polling'\n lastLoggedTransportMode = 'polling'\n } else {\n logTransportState(api, 'websocket', agentEmail, lastLoggedTransportMode)\n lastTransportMode = 'websocket'\n lastLoggedTransportMode = 'websocket'\n }\n }\n\n setTimeout(() => {\n if (!aampClient?.isConnected()) return\n const mode = aampClient.isUsingPollingFallback() ? 'polling' : 'websocket'\n logTransportState(api, mode, agentEmail, lastLoggedTransportMode)\n lastTransportMode = mode\n lastLoggedTransportMode = mode\n }, 1000)\n\n transportMonitorTimer = setInterval(() => {\n if (!aampClient) return\n if (!aampClient.isConnected()) {\n if (lastTransportMode !== 'disconnected') {\n lastTransportMode = 'disconnected'\n }\n return\n }\n const mode = aampClient.isUsingPollingFallback() ? 'polling' : 'websocket'\n logTransportState(api, mode, agentEmail, lastLoggedTransportMode)\n lastTransportMode = mode\n lastLoggedTransportMode = mode\n }, 5000)\n\n reconcileTimer = setInterval(() => {\n if (!aampClient) return\n void aampClient.reconcileRecentEmails(20).catch((err: Error) => {\n lastConnectionError = err.message\n api.logger.warn(`[AAMP] Mailbox reconcile failed: ${err.message}`)\n })\n }, 15000)\n }\n\n // \u2500\u2500 Service: auto-connect at gateway startup, disconnect on shutdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // registerService causes this plugin to load eagerly (at gateway startup),\n // not lazily (on first agent run). start() is called once the gateway is up.\n api.registerService({\n id: 'aamp-service',\n start: async () => {\n if (!cfg.aampHost) {\n api.logger.info('[AAMP] aampHost not configured \u2014 skipping auto-connect')\n return\n }\n try {\n const identity = await resolveIdentity(cfg)\n await doConnect(identity)\n } catch (err) {\n api.logger.warn(`[AAMP] Service auto-connect failed: ${(err as Error).message}`)\n }\n },\n stop: () => {\n if (reconcileTimer) {\n clearInterval(reconcileTimer)\n reconcileTimer = null\n }\n if (transportMonitorTimer) {\n clearInterval(transportMonitorTimer)\n transportMonitorTimer = null\n }\n if (aampClient) {\n try {\n aampClient.disconnect()\n api.logger.info('[AAMP] Disconnected on gateway stop')\n } catch {\n // ignore disconnect errors on shutdown\n }\n }\n },\n })\n\n // \u2500\u2500 gateway_start hook: re-trigger heartbeat after runner is initialized \u2500\u2500\u2500\n // Service start() runs BEFORE the heartbeat runner is ready, so\n // requestHeartbeatNow() called during JMAP initial fetch is silently dropped\n // (handler == null). gateway_start fires AFTER the heartbeat runner starts,\n // so we re-trigger here to process any tasks queued during startup.\n api.on('gateway_start', () => {\n if (pendingTasks.size === 0) return\n api.logger.info(`[AAMP] gateway_start: re-triggering heartbeat for ${pendingTasks.size} pending task(s)`)\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: currentSessionKey })\n } catch (err) {\n api.logger.warn(`[AAMP] gateway_start heartbeat failed: ${(err as Error).message}`)\n }\n })\n\n // \u2500\u2500 2. Prompt injection: surface the oldest pending task to the LLM \u2500\u2500\u2500\u2500\u2500\u2500\n api.on(\n 'before_prompt_build',\n (_event, ctx) => {\n // Keep currentSessionKey fresh \u2014 used by task.dispatch to target the right session.\n // Skip channel dispatch sessions (aamp:*) to avoid polluting the heartbeat session key.\n if (ctx?.sessionKey && !String(ctx.sessionKey).startsWith('aamp:')) {\n currentSessionKey = ctx.sessionKey\n }\n\n // Expire tasks that have exceeded their timeout\n const now = Date.now()\n for (const [id, t] of pendingTasks) {\n if (t.timeoutSecs && now - new Date(t.receivedAt).getTime() > t.timeoutSecs * 1000) {\n api.logger.warn(`[AAMP] Task ${id} timed out \u2014 removing from queue`)\n pendingTasks.delete(id)\n }\n }\n\n if (pendingTasks.size === 0) return {}\n\n // Prioritize notifications (sub-task results/help) over actionable tasks.\n // Without this, the oldest actionable task blocks notification delivery,\n // preventing the LLM from seeing sub-task results and completing the parent task.\n const allEntries = [...pendingTasks.entries()]\n const notifications = allEntries.filter(([key]) => key.startsWith('result:') || key.startsWith('help:'))\n const actionable = allEntries.filter(([key]) => !key.startsWith('result:') && !key.startsWith('help:'))\n\n // Pick notification first if available, otherwise oldest actionable task\n const [taskKey, task] = notifications.length > 0\n ? notifications.sort((a, b) => new Date(a[1].receivedAt).getTime() - new Date(b[1].receivedAt).getTime())[0]\n : actionable.sort((a, b) => new Date(a[1].receivedAt).getTime() - new Date(b[1].receivedAt).getTime())[0]\n\n const isNotification = taskKey.startsWith('result:') || taskKey.startsWith('help:')\n\n // Notifications are one-shot: remove immediately after injecting into prompt\n if (isNotification && taskKey) {\n pendingTasks.delete(taskKey)\n }\n\n // Find remaining actionable tasks (non-notification) that still need a response\n const actionableTasks = [...pendingTasks.entries()]\n .filter(([key]) => !key.startsWith('result:') && !key.startsWith('help:'))\n .map(([, t]) => t)\n\n const hasAttachmentInfo = isNotification && (task.bodyText?.includes('aamp_download_attachment') ?? false)\n const actionRequiredSection = isNotification && actionableTasks.length > 0\n ? [\n ``,\n `### Action Required`,\n ``,\n `You still have ${actionableTasks.length} pending task(s) that need a response.`,\n `Use the sub-task result above to complete them by calling aamp_send_result.`,\n ``,\n ...actionableTasks.map((t) =>\n `- Task ID: ${t.taskId} | From: ${t.from} | Title: \"${t.title}\"`\n ),\n ...(hasAttachmentInfo ? [\n ``,\n `### Forwarding Attachments`,\n `The sub-task result includes file attachments. To forward them:`,\n `1. Call aamp_download_attachment for each blobId listed above`,\n `2. Include the downloaded files in aamp_send_result via the attachments parameter`,\n ` Example: attachments: [{ filename: \"file.html\", path: \"/tmp/aamp-files/file.html\" }]`,\n ] : []),\n ].join('\\n')\n : ''\n\n const lines = isNotification ? [\n `## Sub-task Update`,\n ``,\n `A sub-task you dispatched has returned a result. Review the information below.`,\n `If the sub-task included attachments, use aamp_download_attachment to fetch them.`,\n ``,\n `Task ID: ${task.taskId}`,\n `From: ${task.from}`,\n `Title: ${task.title}`,\n task.bodyText ? `\\n${task.bodyText}` : '',\n actionRequiredSection,\n pendingTasks.size > 1 ? `\\n(+${pendingTasks.size - 1} more items queued)` : '',\n ] : [\n `## Pending AAMP Task (action required)`,\n ``,\n `You have received a task via AAMP email. You MUST call one of the two tools below`,\n `BEFORE responding to the user \u2014 do not skip this step.`,\n ``,\n `### Tool selection rules (follow strictly):`,\n ``,\n `Use aamp_send_result ONLY when ALL of the following are true:`,\n ` 1. The title contains a clear, specific action verb (e.g. \"summarise\", \"review\",`,\n ` \"translate\", \"generate\", \"fix\", \"search\", \"compare\", \"list\")`,\n ` 2. You know exactly what input/resource to act on`,\n ` 3. No ambiguity remains \u2014 you could start work immediately without asking anything`,\n ``,\n `Use aamp_send_help in ALL other cases, including:`,\n ` - Title is a greeting or salutation (\"hello\", \"hi\", \"hey\", \"test\", \"ping\", etc.)`,\n ` - Title is fewer than 4 words and contains no actionable verb`,\n ` - Title is too vague to act on without guessing (e.g. \"help\", \"task\", \"question\")`,\n ` - Required context is missing (which file? which URL? which criteria?)`,\n ` - Multiple interpretations are equally plausible`,\n ``,\n `IMPORTANT: Responding to a greeting with a greeting is WRONG. \"hello\" is not a`,\n `valid task description \u2014 ask what specific task the dispatcher needs done.`,\n ``,\n `### Sub-task dispatch rules:`,\n `If you delegate work to another agent via aamp_dispatch_task, you MUST pass`,\n `parentTaskId: \"${task.taskId}\" to establish the parent-child relationship.`,\n ``,\n `Task ID: ${task.taskId}`,\n `From: ${task.from}`,\n `Title: ${task.title}`,\n task.bodyText ? `Description:\\n${task.bodyText}` : '',\n task.contextLinks.length\n ? `Context Links:\\n${task.contextLinks.map((l) => ` - ${l}`).join('\\n')}`\n : '',\n task.timeoutSecs ? `Deadline: ${task.timeoutSecs}s from dispatch` : `Deadline: none`,\n `Received: ${task.receivedAt}`,\n pendingTasks.size > 1 ? `\\n(+${pendingTasks.size - 1} more tasks queued)` : '',\n ]\n .filter(Boolean)\n .join('\\n')\n\n return { prependContext: lines }\n },\n { priority: 5 },\n )\n\n // \u2500\u2500 3. Tool: send task result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_send_result',\n description:\n 'Send the result of an AAMP task back to the dispatcher. ' +\n 'Call this after you have finished processing the task.',\n parameters: {\n type: 'object',\n required: ['taskId', 'status', 'output'],\n properties: {\n taskId: {\n type: 'string',\n description: 'The AAMP task ID to reply to (from the system context)',\n },\n status: {\n type: 'string',\n enum: ['completed', 'rejected'],\n description: '\"completed\" on success, \"rejected\" if the task cannot be done',\n },\n output: {\n type: 'string',\n description: 'Your result or explanation',\n },\n errorMsg: {\n type: 'string',\n description: 'Optional error details (use only when status = rejected)',\n },\n attachments: {\n type: 'array',\n description: 'File attachments. Each item: { filename, contentType, path (local file path) }',\n items: {\n type: 'object',\n properties: {\n filename: { type: 'string' },\n contentType: { type: 'string' },\n path: { type: 'string', description: 'Absolute path to the file on disk' },\n },\n required: ['filename', 'path'],\n },\n },\n structuredResult: {\n type: 'array',\n description: 'Optional structured Meego field values.',\n items: {\n type: 'object',\n required: ['fieldKey', 'fieldTypeKey'],\n properties: {\n fieldKey: { type: 'string' },\n fieldTypeKey: { type: 'string' },\n fieldAlias: { type: 'string' },\n value: {\n description: 'Field value in the exact format required by Meego for this field type.',\n },\n index: { type: 'string' },\n attachmentFilenames: {\n type: 'array',\n items: { type: 'string' },\n description: 'For attachment fields, filenames from attachments[] that should be uploaded into this field.',\n },\n },\n },\n },\n },\n },\n execute: async (_id, params) => {\n const p = params as {\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n attachments?: Array<{ filename: string; contentType?: string; path: string }>\n structuredResult?: StructuredResultFieldInput[]\n }\n\n const task = pendingTasks.get(p.taskId)\n if (!task) {\n return {\n content: [{ type: 'text', text: `Error: task ${p.taskId} not found in pending queue.` }],\n }\n }\n\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n api.logger.info(`[AAMP] aamp_send_result params ${JSON.stringify({\n taskId: p.taskId,\n status: p.status,\n output: p.output,\n errorMsg: p.errorMsg,\n attachments: p.attachments?.map((a) => ({\n filename: a.filename,\n contentType: a.contentType ?? 'application/octet-stream',\n path: a.path,\n })) ?? [],\n structuredResult: p.structuredResult?.map((field) => ({\n fieldKey: field.fieldKey,\n fieldTypeKey: field.fieldTypeKey,\n fieldAlias: field.fieldAlias,\n value: field.value,\n index: field.index,\n attachmentFilenames: field.attachmentFilenames ?? [],\n })) ?? [],\n })}`)\n\n // Build attachments from file paths\n let attachments: AampAttachment[] | undefined\n if (p.attachments?.length) {\n attachments = p.attachments.map((a: { filename: string; contentType?: string; path: string }) => ({\n filename: a.filename,\n contentType: a.contentType ?? 'application/octet-stream',\n content: readBinaryFile(a.path),\n }))\n }\n\n await aampClient.sendResult({\n to: task.from,\n taskId: task.taskId,\n status: p.status,\n output: p.output,\n errorMsg: p.errorMsg,\n structuredResult: p.structuredResult?.length ? p.structuredResult : undefined,\n inReplyTo: task.messageId || undefined,\n attachments,\n })\n\n pendingTasks.delete(task.taskId)\n api.logger.info(`[AAMP] \u2192 task.result ${task.taskId} ${p.status}`)\n\n // If more tasks remain, wake the agent to process them\n if (pendingTasks.size > 0) {\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: currentSessionKey })\n } catch { /* ignore */ }\n }\n\n return {\n content: [\n {\n type: 'text',\n text: `Result sent for task ${task.taskId} (status: ${p.status}).`,\n },\n ],\n }\n },\n }, { name: 'aamp_send_result' })\n\n // \u2500\u2500 4. Tool: ask for help \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_send_help',\n description:\n 'Send a help request for an AAMP task when you are blocked or need human clarification ' +\n 'before you can proceed.',\n parameters: {\n type: 'object',\n required: ['taskId', 'question', 'blockedReason'],\n properties: {\n taskId: {\n type: 'string',\n description: 'The AAMP task ID',\n },\n question: {\n type: 'string',\n description: 'Your question for the human dispatcher',\n },\n blockedReason: {\n type: 'string',\n description: 'Why you cannot proceed without their input',\n },\n suggestedOptions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional list of choices for the dispatcher to pick from',\n },\n },\n },\n execute: async (_id, params) => {\n const p = params as {\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions?: string[]\n }\n\n const task = pendingTasks.get(p.taskId)\n if (!task) {\n return {\n content: [{ type: 'text', text: `Error: task ${p.taskId} not found in pending queue.` }],\n }\n }\n\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n await aampClient.sendHelp({\n to: task.from,\n taskId: task.taskId,\n question: p.question,\n blockedReason: p.blockedReason,\n suggestedOptions: p.suggestedOptions ?? [],\n inReplyTo: task.messageId || undefined,\n })\n\n api.logger.info(`[AAMP] \u2192 task.help ${task.taskId}`)\n\n // Keep the task in pending \u2014 the help reply may arrive later\n return {\n content: [\n {\n type: 'text',\n text: `Help request sent for task ${task.taskId}. The task remains pending until the dispatcher replies.`,\n },\n ],\n }\n },\n }, { name: 'aamp_send_help' })\n\n // \u2500\u2500 5. Tool: inspect queue \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_pending_tasks',\n description: 'List all AAMP tasks currently waiting to be processed.',\n parameters: { type: 'object', properties: {} },\n execute: async () => {\n if (pendingTasks.size === 0) {\n return { content: [{ type: 'text', text: 'No pending AAMP tasks.' }] }\n }\n\n const lines = [...pendingTasks.values()]\n .sort((a, b) => new Date(a.receivedAt).getTime() - new Date(b.receivedAt).getTime())\n .map(\n (t, i) =>\n `${i + 1}. [${t.taskId}] \"${t.title}\"${t.bodyText ? `\\n Description: ${t.bodyText}` : ''} \u2014 from ${t.from} (received ${t.receivedAt})`,\n )\n\n return {\n content: [\n {\n type: 'text',\n text: `${pendingTasks.size} pending task(s):\\n${lines.join('\\n')}`,\n },\n ],\n }\n },\n }, { name: 'aamp_pending_tasks' })\n\n // \u2500\u2500 6. Tool: dispatch task to another agent (SYNCHRONOUS) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Sends the task and BLOCKS until the sub-agent replies with task.result or\n // task.help. The reply is returned directly as the tool result, keeping the\n // LLM awake with full context \u2014 no heartbeat/channel dispatch needed.\n api.registerTool({\n name: 'aamp_dispatch_task',\n description:\n 'Send a task to another AAMP agent and WAIT for the result. ' +\n 'This tool blocks until the sub-agent replies (typically 5-60s). ' +\n 'The sub-agent\\'s output and any attachment file paths are returned directly.',\n parameters: {\n type: 'object',\n required: ['to', 'title'],\n properties: {\n to: { type: 'string', description: 'Target agent AAMP email address' },\n title: { type: 'string', description: 'Task title (concise summary)' },\n bodyText: { type: 'string', description: 'Detailed task description' },\n parentTaskId: { type: 'string', description: 'If you are processing a pending AAMP task, pass its Task ID here to establish parent-child nesting. Omit for top-level tasks.' },\n timeoutSecs: { type: 'number', description: 'Timeout in seconds (optional)' },\n contextLinks: {\n type: 'array', items: { type: 'string' },\n description: 'URLs providing context (optional)',\n },\n attachments: {\n type: 'array',\n description: 'File attachments. Each item: { filename, contentType, path (local file path) }',\n items: {\n type: 'object',\n properties: {\n filename: { type: 'string' },\n contentType: { type: 'string' },\n path: { type: 'string', description: 'Absolute path to the file on disk' },\n },\n required: ['filename', 'path'],\n },\n },\n },\n },\n execute: async (_id: unknown, params: {\n to: string; title: string; bodyText?: string;\n parentTaskId?: string; timeoutSecs?: number; contextLinks?: string[];\n attachments?: Array<{ filename: string; contentType?: string; path: string }>\n }) => {\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n try {\n // Build attachments from file paths\n let attachments: AampAttachment[] | undefined\n if (params.attachments?.length) {\n attachments = params.attachments.map((a: { filename: string; contentType?: string; path: string }) => ({\n filename: a.filename,\n contentType: a.contentType ?? 'application/octet-stream',\n content: readBinaryFile(a.path),\n }))\n }\n\n const result = await aampClient.sendTask({\n to: params.to,\n title: params.title,\n parentTaskId: params.parentTaskId,\n timeoutSecs: params.timeoutSecs,\n contextLinks: params.contextLinks,\n attachments,\n })\n\n // Track as dispatched sub-task\n dispatchedSubtasks.set(result.taskId, {\n to: params.to,\n title: params.title,\n dispatchedAt: new Date().toISOString(),\n parentTaskId: params.parentTaskId,\n })\n\n api.logger.info(`[AAMP] \u2192 task.dispatch ${result.taskId} to=${params.to} parent=${params.parentTaskId ?? 'none'} (waiting for reply\u2026)`)\n\n // \u2500\u2500 SYNCHRONOUS WAIT: block until sub-agent replies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const timeoutMs = (params.timeoutSecs ?? 300) * 1000\n const reply = await new Promise<{ type: 'result' | 'help'; data: unknown }>((resolve, reject) => {\n waitingDispatches.set(result.taskId, resolve)\n setTimeout(() => {\n if (waitingDispatches.delete(result.taskId)) {\n reject(new Error(`Sub-task ${result.taskId} timed out after ${params.timeoutSecs ?? 300}s`))\n }\n }, timeoutMs)\n })\n\n api.logger.info(`[AAMP] \u2190 sync reply for ${result.taskId}: type=${reply.type} attachments=${JSON.stringify((reply.data as any)?.attachments?.length ?? 0)}`)\n\n if (reply.type === 'result') {\n const r = reply.data as TaskResult\n\n // Pre-download attachments \u2014 use direct JMAP blob download (bypass SDK's downloadBlob\n // which was returning 404 due to URL construction issues in the esbuild bundle).\n let attachmentLines = ''\n if (r.attachments?.length) {\n api.logger.info(`[AAMP] Downloading ${r.attachments.length} attachment(s) from sync reply...`)\n const dir = '/tmp/aamp-files'\n ensureDir(dir)\n const downloaded: string[] = []\n const base = baseUrl(cfg.aampHost)\n const identity = loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath())\n const authHeader = identity ? `Basic ${Buffer.from(identity.email + ':' + identity.smtpPassword).toString('base64')}` : ''\n for (const att of r.attachments) {\n try {\n // Direct JMAP blob download \u2014 construct URL manually\n const dlUrl = `${base}/jmap/download/n/${encodeURIComponent(att.blobId)}/${encodeURIComponent(att.filename)}?accept=application/octet-stream`\n api.logger.info(`[AAMP] Fetching ${dlUrl}`)\n const dlRes = await fetch(dlUrl, { headers: { Authorization: authHeader } })\n if (!dlRes.ok) throw new Error(`HTTP ${dlRes.status}`)\n const buffer = Buffer.from(await dlRes.arrayBuffer())\n const filepath = `${dir}/${att.filename}`\n writeBinaryFile(filepath, buffer)\n downloaded.push(`${att.filename} (${(buffer.length / 1024).toFixed(1)} KB) \u2192 ${filepath}`)\n api.logger.info(`[AAMP] Downloaded: ${att.filename} (${(buffer.length / 1024).toFixed(1)} KB)`)\n } catch (dlErr) {\n api.logger.error(`[AAMP] Download failed for ${att.filename}: ${(dlErr as Error).message}`)\n }\n }\n if (downloaded.length) {\n attachmentLines = `\\n\\nAttachments downloaded:\\n${downloaded.join('\\n')}`\n }\n }\n\n return {\n content: [{\n type: 'text',\n text: [\n `Sub-task ${r.status}: ${params.title}`,\n `Agent: ${r.from}`,\n `Task ID: ${result.taskId}`,\n r.status === 'completed' ? `\\nOutput:\\n${r.output}` : `\\nError: ${r.errorMsg ?? 'rejected'}`,\n attachmentLines,\n ].filter(Boolean).join('\\n'),\n }],\n }\n } else {\n const h = reply.data as TaskHelp\n return {\n content: [{\n type: 'text',\n text: [\n `Sub-task needs help: ${params.title}`,\n `Agent: ${h.from}`,\n `Task ID: ${result.taskId}`,\n `\\nQuestion: ${h.question}`,\n `Blocked reason: ${h.blockedReason}`,\n h.suggestedOptions?.length ? `Options: ${h.suggestedOptions.join(' | ')}` : '',\n ].filter(Boolean).join('\\n'),\n }],\n }\n }\n } catch (err) {\n return {\n content: [{ type: 'text', text: `Error dispatching task: ${(err as Error).message}` }],\n }\n }\n },\n }, { name: 'aamp_dispatch_task' })\n\n // \u2500\u2500 7. Tool: check AAMP protocol support \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_check_protocol',\n description:\n 'Check if an email address supports the AAMP protocol. ' +\n 'Returns { aamp: true/false } indicating whether the address is an AAMP agent.',\n parameters: {\n type: 'object',\n required: ['email'],\n properties: {\n email: { type: 'string', description: 'Email address to check' },\n },\n },\n execute: async (_id: unknown, params: { email: string }) => {\n const base = baseUrl(cfg.aampHost)\n const email = params?.email ?? ''\n if (!email) {\n return { content: [{ type: 'text', text: 'Error: email parameter is required' }] }\n }\n try {\n const res = await fetch(`${base}/api/aamp-check?email=${encodeURIComponent(email)}`)\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json() as { aamp: boolean; domain?: string }\n return {\n content: [{\n type: 'text',\n text: data.aamp\n ? `${params.email} supports AAMP protocol (domain: ${data.domain ?? 'unknown'})`\n : `${params.email} does not support AAMP protocol`,\n }],\n }\n } catch (err) {\n return {\n content: [{ type: 'text', text: `Could not check ${params.email}: ${(err as Error).message}` }],\n }\n }\n },\n }, { name: 'aamp_check_protocol' })\n\n // \u2500\u2500 8. Tool: download attachment blob \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_download_attachment',\n description:\n 'Download an AAMP email attachment to local disk by its blobId. ' +\n 'Use this to retrieve files received from sub-agent task results.',\n parameters: {\n type: 'object',\n required: ['blobId', 'filename'],\n properties: {\n blobId: { type: 'string', description: 'The JMAP blobId from the attachment metadata' },\n filename: { type: 'string', description: 'Filename to save as' },\n saveTo: { type: 'string', description: 'Directory to save to (default: /tmp/aamp-files)' },\n },\n },\n execute: async (_id: unknown, params: { blobId: string; filename: string; saveTo?: string }) => {\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n const dir = params.saveTo ?? '/tmp/aamp-files'\n ensureDir(dir)\n\n try {\n const buffer = await aampClient.downloadBlob(params.blobId, params.filename)\n const filepath = `${dir}/${params.filename}`\n writeBinaryFile(filepath, buffer)\n return {\n content: [{\n type: 'text',\n text: `Downloaded ${params.filename} (${(buffer.length / 1024).toFixed(1)} KB) to ${filepath}`,\n }],\n }\n } catch (err) {\n return {\n content: [{ type: 'text', text: `Download failed: ${(err as Error).message}` }],\n }\n }\n },\n }, { name: 'aamp_download_attachment' })\n\n // \u2500\u2500 9. Slash command: /aamp-status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerCommand({\n name: 'aamp-status',\n description: 'Show AAMP connection status and pending task queue',\n acceptsArgs: false,\n requireAuth: false,\n handler: () => {\n const isPollingFallback = aampClient?.isUsingPollingFallback?.() ?? false\n const connectionLine = aampClient?.isConnected()\n ? (isPollingFallback ? '\uD83D\uDFE1 connected (polling fallback)' : '\u2705 connected')\n : '\u274C disconnected'\n\n return {\n text: [\n `**AAMP Plugin Status**`,\n `Host: ${cfg.aampHost || '(not configured)'}`,\n `Identity: ${agentEmail || '(not yet registered)'}`,\n `Connection: ${connectionLine}`,\n `Cached: ${loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath()) ? 'yes' : 'no'}`,\n lastConnectionError ? `Last error: ${lastConnectionError}` : '',\n lastDisconnectReason ? `Last disconnect: ${lastDisconnectReason}` : '',\n `Pending: ${pendingTasks.size} task(s)`,\n ...[...pendingTasks.values()].map(\n (t) => ` \u2022 ${t.taskId.slice(0, 8)}\u2026 \"${t.title}\" from ${t.from}`,\n ),\n ]\n .filter(Boolean)\n .join('\\n'),\n }\n },\n })\n },\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * JMAP WebSocket Push Client\n *\n * Connects to Stalwart's JMAP WebSocket endpoint and subscribes to\n * Email StateChange events. When a new email arrives in the agent's\n * mailbox, fetches it via JMAP and emits the parsed AAMP headers.\n *\n * Protocol: RFC 8887 (JMAP over WebSocket)\n * Ref: https://www.rfc-editor.org/rfc/rfc8887\n */\n\nimport WebSocket from 'ws'\nimport { parseAampHeaders } from './parser.js'\nimport type { AampMessage, HumanReply, TaskAck, TaskDispatch, TaskHelp, TaskResult } from './types.js'\nimport { TinyEmitter } from './tiny-emitter.js'\n\ninterface JmapSession {\n capabilities: Record<string, unknown>\n accounts: Record<string, { name: string; isPrimary: boolean; accountCapabilities: Record<string, unknown> }>\n primaryAccounts: Record<string, string>\n username: string\n apiUrl: string\n downloadUrl: string\n uploadUrl: string\n eventSourceUrl: string\n state: string\n}\n\ninterface JmapStateChange {\n '@type': 'StateChange'\n changed: Record<string, Record<string, string>>\n pushState?: string\n}\n\ninterface JmapEmail {\n id: string\n blobId: string\n threadId: string\n mailboxIds: Record<string, boolean>\n subject: string\n from: Array<{ email: string; name?: string }>\n to: Array<{ email: string; name?: string }>\n replyTo?: Array<{ email: string; name?: string }>\n messageId?: string[]\n headers: Array<{ name: string; value: string }>\n receivedAt: string\n size: number\n /** Plain-text body parts (JMAP bodyStructure) */\n textBody?: Array<{ partId: string; type: string }>\n /** Decoded body values keyed by partId */\n bodyValues?: Record<string, { value: string; isEncodingProblem?: boolean; isTruncated?: boolean }>\n /** JMAP attachments (non-inline parts) */\n attachments?: Array<{\n blobId: string\n type: string\n name: string | null\n size: number\n }>\n}\n\ninterface JmapMethodResponse {\n methodResponses: Array<[string, Record<string, unknown>, string]>\n}\n\nfunction describeError(err: unknown): string {\n if (!(err instanceof Error)) return String(err)\n\n const parts = [err.message]\n const details = err as Error & {\n code?: string\n errno?: number | string\n syscall?: string\n address?: string\n port?: number\n cause?: unknown\n }\n\n if (details.code) parts.push(`code=${details.code}`)\n if (details.errno !== undefined) parts.push(`errno=${details.errno}`)\n if (details.syscall) parts.push(`syscall=${details.syscall}`)\n if (details.address) parts.push(`address=${details.address}`)\n if (details.port !== undefined) parts.push(`port=${details.port}`)\n\n if (details.cause instanceof Error) {\n parts.push(`cause=${describeError(details.cause)}`)\n } else if (details.cause !== undefined) {\n parts.push(`cause=${String(details.cause)}`)\n }\n\n return parts.join(' | ')\n}\n\ntype JmapPushEvents = {\n 'task.dispatch': (task: TaskDispatch) => void\n 'task.result': (result: TaskResult) => void\n 'task.help_needed': (help: TaskHelp) => void\n 'task.help': (help: TaskHelp) => void\n 'task.ack': (ack: TaskAck) => void\n reply: (reply: HumanReply) => void\n connected: () => void\n disconnected: (reason: string) => void\n error: (err: Error) => void\n _autoAck: (payload: { to: string; taskId: string; messageId: string }) => void\n}\n\nexport class JmapPushClient extends TinyEmitter<JmapPushEvents> {\n private ws: WebSocket | null = null\n private session: JmapSession | null = null\n private reconnectTimer: NodeJS.Timeout | null = null\n private pollTimer: NodeJS.Timeout | null = null\n private pingTimer: NodeJS.Timeout | null = null\n private safetySyncTimer: NodeJS.Timeout | null = null\n private readonly seenMessageIds = new Set<string>()\n private connected = false\n private pollingActive = false\n private running = false\n private connecting = false\n /** JMAP Email state \u2014 tracks processed position; null = not yet initialized */\n private emailState: string | null = null\n private readonly startedAtMs = Date.now()\n\n private readonly email: string\n private readonly password: string\n private readonly jmapUrl: string\n private readonly reconnectInterval: number\n private readonly rejectUnauthorized: boolean\n private readonly pingIntervalMs = 5000\n private readonly safetySyncIntervalMs = 5000\n\n constructor(opts: {\n email: string\n password: string\n jmapUrl: string\n reconnectInterval?: number\n /** Whether to reject unauthorized TLS certificates (default: true) */\n rejectUnauthorized?: boolean\n }) {\n super()\n this.email = opts.email\n this.password = opts.password\n this.jmapUrl = opts.jmapUrl.replace(/\\/$/, '')\n this.reconnectInterval = opts.reconnectInterval ?? 5000\n this.rejectUnauthorized = opts.rejectUnauthorized ?? true\n }\n\n /**\n * Start the JMAP Push listener\n */\n async start(): Promise<void> {\n this.running = true\n this.startSafetySync()\n await this.connect()\n }\n\n /**\n * Stop the JMAP Push listener\n */\n stop(): void {\n this.running = false\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n if (this.pollTimer) {\n clearTimeout(this.pollTimer)\n this.pollTimer = null\n }\n if (this.pingTimer) {\n clearInterval(this.pingTimer)\n this.pingTimer = null\n }\n if (this.safetySyncTimer) {\n clearInterval(this.safetySyncTimer)\n this.safetySyncTimer = null\n }\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n this.connected = false\n this.pollingActive = false\n this.connecting = false\n }\n\n private getAuthHeader(): string {\n const creds = `${this.email}:${this.password}`\n return `Basic ${Buffer.from(creds).toString('base64')}`\n }\n\n /**\n * Fetch the JMAP session object\n */\n private async fetchSession(): Promise<JmapSession> {\n const url = `${this.jmapUrl}/.well-known/jmap`\n let res: Response\n try {\n res = await fetch(url, {\n headers: { Authorization: this.getAuthHeader() },\n })\n } catch (err) {\n throw new Error(`fetchSession ${url} failed: ${describeError(err)}`)\n }\n\n if (!res.ok) {\n throw new Error(`Failed to fetch JMAP session: ${res.status} ${res.statusText}`)\n }\n\n return res.json() as Promise<JmapSession>\n }\n\n /**\n * Perform a JMAP API call\n */\n private async jmapCall(\n methods: Array<[string, Record<string, unknown>, string]>,\n ): Promise<JmapMethodResponse> {\n if (!this.session) throw new Error('No JMAP session')\n\n // Use the configured jmapUrl (external hostname) rather than session.apiUrl\n // which Stalwart populates with its own internal URL (e.g. http://aamp.local:8080/jmap)\n // and is unreachable when running behind a proxy.\n const apiUrl = `${this.jmapUrl}/jmap/`\n let res: Response\n try {\n res = await fetch(apiUrl, {\n method: 'POST',\n headers: {\n Authorization: this.getAuthHeader(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n using: [\n 'urn:ietf:params:jmap:core',\n 'urn:ietf:params:jmap:mail',\n ],\n methodCalls: methods,\n }),\n })\n } catch (err) {\n throw new Error(`jmapCall ${apiUrl} failed: ${describeError(err)}`)\n }\n\n if (!res.ok) {\n throw new Error(`JMAP API call failed: ${res.status}`)\n }\n\n return res.json() as Promise<JmapMethodResponse>\n }\n\n /**\n * Initialize emailState by fetching the current state without loading any emails.\n * Called on first connect so we only process emails that arrive AFTER this point.\n */\n private async initEmailState(accountId: string): Promise<void> {\n const response = await this.jmapCall([\n ['Email/get', { accountId, ids: [] }, 'g0'],\n ])\n const getResp = response.methodResponses.find(([name]) => name === 'Email/get')\n if (getResp) {\n this.emailState = (getResp[1] as { state?: string }).state ?? null\n }\n }\n\n /**\n * Fetch only emails created since `sinceState` using Email/changes.\n * Updates `this.emailState` to the new state after fetching.\n * Returns [] and resets state if the server cannot calculate changes (state too old).\n */\n private async fetchEmailsSince(accountId: string, sinceState: string): Promise<JmapEmail[]> {\n const changesResp = await this.jmapCall([\n ['Email/changes', { accountId, sinceState, maxChanges: 50 }, 'c1'],\n ])\n\n const changesResult = changesResp.methodResponses.find(([name]) => name === 'Email/changes')\n\n // Handle server error \u2014 e.g. \"cannotCalculateChanges\" when state is too old\n if (!changesResult || changesResult[0] === 'error') {\n await this.initEmailState(accountId)\n return []\n }\n\n const changes = changesResult[1] as {\n created?: string[]\n newState?: string\n hasMoreChanges?: boolean\n }\n\n if (changes.newState) {\n this.emailState = changes.newState\n }\n\n const newIds = changes.created ?? []\n if (newIds.length === 0) return []\n\n const emailResp = await this.jmapCall([\n [\n 'Email/get',\n {\n accountId,\n ids: newIds,\n properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],\n fetchTextBodyValues: true,\n maxBodyValueBytes: 262144,\n },\n 'g1',\n ],\n ])\n\n const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get')\n if (!getResult) return []\n\n const data = getResult[1] as { list?: JmapEmail[] }\n return data.list ?? []\n }\n\n /**\n * Process a received email.\n *\n * Priority:\n * 1. If X-AAMP-Intent is present \u2192 emit typed AAMP event (task.dispatch / task.result / task.help_needed)\n * 2. If In-Reply-To is present \u2192 emit 'reply' event so the application layer can\n * resolve the thread (inReplyTo \u2192 taskId via Redis/DB) and handle human replies.\n * 3. Otherwise \u2192 ignore (not an AAMP-related email)\n */\n private processEmail(email: JmapEmail): void {\n // Build lowercase header map from JMAP header array\n const headerMap: Record<string, string> = {}\n for (const h of email.headers ?? []) {\n headerMap[h.name.toLowerCase()] = h.value.trim()\n }\n\n const fromAddr = email.from?.[0]?.email ?? ''\n const toAddr = email.to?.[0]?.email ?? ''\n const messageId = email.messageId?.[0] ?? email.id\n\n if (this.seenMessageIds.has(messageId)) return\n this.seenMessageIds.add(messageId)\n\n // \u2500\u2500 Path 1: AAMP-tagged email \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const msg: AampMessage | null = parseAampHeaders({\n from: fromAddr,\n to: toAddr,\n messageId,\n subject: email.subject ?? '',\n headers: headerMap,\n })\n\n if (msg && 'intent' in msg) {\n // Attach email body text (task description) to all AAMP messages\n const aampTextPartId = email.textBody?.[0]?.partId\n const aampBodyText = aampTextPartId ? (email.bodyValues?.[aampTextPartId]?.value ?? '').trim() : ''\n ;(msg as unknown as Record<string, unknown>).bodyText = aampBodyText\n\n // Attach received attachment metadata (blobId-based, downloadable via downloadBlob)\n const receivedAttachments = (email.attachments ?? []).map(a => ({\n filename: a.name ?? 'attachment',\n contentType: a.type,\n size: a.size,\n blobId: a.blobId,\n }))\n if (receivedAttachments.length > 0) {\n ;(msg as unknown as Record<string, unknown>).attachments = receivedAttachments\n }\n\n // Auto-ACK for dispatches \u2014 AampClient handles the actual sending\n if ((msg as { intent: string }).intent === 'task.dispatch') {\n this.emit('_autoAck', { to: fromAddr, taskId: (msg as { taskId: string }).taskId, messageId })\n }\n\n const aampMsg = msg as Exclude<AampMessage, HumanReply>\n switch (aampMsg.intent) {\n case 'task.dispatch':\n this.emit('task.dispatch', aampMsg)\n break\n case 'task.result':\n this.emit('task.result', aampMsg)\n break\n case 'task.help_needed':\n this.emit('task.help_needed', aampMsg)\n this.emit('task.help', aampMsg)\n break\n case 'task.ack':\n this.emit('task.ack', aampMsg)\n break\n }\n return\n }\n\n // \u2500\u2500 Path 2: standard email reply \u2014 In-Reply-To fallback \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Standard email clients automatically set In-Reply-To when replying.\n // We strip angle brackets (<msgid@host>) to get the bare Message-ID.\n const rawInReplyTo = headerMap['in-reply-to'] ?? ''\n if (!rawInReplyTo) return // unrelated email, ignore\n\n // Handle \"References\" chain: prefer the last (most recent) Message-ID\n // so multi-turn threads still resolve to the correct task.\n const rawReferences = headerMap['references'] ?? ''\n const referencesIds = rawReferences\n .split(/\\s+/)\n .map((s) => s.replace(/[<>]/g, '').trim())\n .filter(Boolean)\n\n const inReplyTo = rawInReplyTo.replace(/[<>]/g, '').trim()\n\n // Extract plain-text body if available (fetched via fetchTextBodyValues)\n const textPartId = email.textBody?.[0]?.partId\n const bodyText = textPartId ? (email.bodyValues?.[textPartId]?.value ?? '').trim() : ''\n\n const reply: HumanReply = {\n inReplyTo,\n messageId,\n from: fromAddr,\n to: toAddr,\n subject: email.subject ?? '',\n bodyText,\n }\n\n // Also expose the full References chain so callers can walk the thread if needed\n if (referencesIds.length > 0) {\n Object.assign(reply, { references: referencesIds })\n }\n\n this.emit('reply', reply)\n }\n\n private async fetchRecentEmails(accountId: string): Promise<JmapEmail[]> {\n const queryResp = await this.jmapCall([\n [\n 'Email/query',\n {\n accountId,\n sort: [{ property: 'receivedAt', isAscending: false }],\n limit: 20,\n },\n 'q1',\n ],\n ])\n\n const queryResult = queryResp.methodResponses.find(([name]) => name === 'Email/query')\n if (!queryResult) return []\n\n const ids = ((queryResult[1] as { ids?: string[] }).ids ?? []).slice(0, 20)\n if (ids.length === 0) return []\n\n const emailResp = await this.jmapCall([\n [\n 'Email/get',\n {\n accountId,\n ids,\n properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],\n fetchTextBodyValues: true,\n maxBodyValueBytes: 262144,\n },\n 'gRecent',\n ],\n ])\n\n const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get')\n if (!getResult) return []\n\n return (getResult[1] as { list?: JmapEmail[] }).list ?? []\n }\n\n private shouldProcessBootstrapEmail(email: JmapEmail): boolean {\n const receivedAtMs = new Date(email.receivedAt).getTime()\n // Keep a small grace window for mail that arrived during startup / reconnect races,\n // but do not replay older historical mailbox contents as fresh tasks.\n return Number.isFinite(receivedAtMs) && receivedAtMs >= this.startedAtMs - 15_000\n }\n\n /**\n * Connect to JMAP WebSocket\n */\n private async connect(): Promise<void> {\n if (this.connecting || !this.running) return\n this.connecting = true\n\n try {\n this.session = await this.fetchSession()\n } catch (err) {\n this.connecting = false\n this.emit('error', new Error(`Failed to get JMAP session: ${(err as Error).message}`))\n this.startPolling('session fetch failed')\n this.scheduleReconnect()\n return\n }\n\n // Build WebSocket URL from the configured jmapUrl (the management-service proxy).\n // The management service exposes the standard external WebSocket path /jmap/ws\n // and proxies upgrades to Stalwart. We never use the session capability URL\n // directly because Stalwart populates it with its own internal hostname\n // (e.g. ws://aamp.local:8080/jmap/ws), which is unreachable from outside\n // the Docker / cluster network.\n const stalwartWsUrl = `${this.jmapUrl}/jmap/ws`\n .replace(/^https:\\/\\//, 'wss://')\n .replace(/^http:\\/\\//, 'ws://')\n\n this.ws = new WebSocket(stalwartWsUrl, 'jmap', {\n headers: {\n Authorization: this.getAuthHeader(),\n },\n perMessageDeflate: false,\n rejectUnauthorized: this.rejectUnauthorized,\n })\n\n this.ws.on('unexpected-response', (_req, res) => {\n this.connecting = false\n const headerSummary = Object.entries(res.headers)\n .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(', ') : (value ?? '')}`)\n .join('; ')\n this.startPolling(`websocket handshake failed: ${res.statusCode ?? 'unknown'}`)\n this.emit(\n 'error',\n new Error(\n `JMAP WebSocket handshake failed: ${res.statusCode ?? 'unknown'} ${res.statusMessage ?? ''}${headerSummary ? ` | headers: ${headerSummary}` : ''}`,\n ),\n )\n this.scheduleReconnect()\n })\n\n this.ws.on('open', async () => {\n this.connecting = false\n this.connected = true\n this.stopPolling()\n this.startPingHeartbeat()\n\n // On first connect (emailState is null), initialize state so we only\n // process emails arriving AFTER this point.\n // On reconnect, emailState is already set \u2014 Email/changes will catch up.\n const accountId = this.session?.primaryAccounts['urn:ietf:params:jmap:mail']\n if (accountId && this.emailState === null) {\n await this.initEmailState(accountId)\n }\n\n // Subscribe to Email state changes AFTER state is initialized\n this.ws!.send(\n JSON.stringify({\n '@type': 'WebSocketPushEnable',\n dataTypes: ['Email'],\n pushState: null,\n }),\n )\n\n this.emit('connected')\n })\n\n this.ws.on('pong', () => {\n // Receiving pong confirms the upstream and LB path are still alive.\n })\n\n this.ws.on('message', async (rawData: WebSocket.RawData) => {\n try {\n const msg = JSON.parse(rawData.toString()) as {\n '@type': string\n } & JmapStateChange\n\n if (msg['@type'] === 'StateChange') {\n await this.handleStateChange(msg)\n }\n } catch (err) {\n this.emit('error', new Error(`Failed to process JMAP push message: ${(err as Error).message}`))\n }\n })\n\n this.ws.on('close', (code, reason) => {\n this.connecting = false\n this.connected = false\n this.stopPingHeartbeat()\n const reasonStr = reason?.toString() ?? 'connection closed'\n this.startPolling(reasonStr)\n this.emit('disconnected', reasonStr)\n\n if (this.running) {\n this.scheduleReconnect()\n }\n })\n\n this.ws.on('error', (err) => {\n this.connecting = false\n this.stopPingHeartbeat()\n this.startPolling(err.message)\n this.emit('error', err)\n })\n }\n\n private startPingHeartbeat(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer)\n this.pingTimer = null\n }\n\n this.pingTimer = setInterval(() => {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n try {\n this.ws.ping()\n } catch (err) {\n this.emit('error', new Error(`Failed to send WebSocket ping: ${(err as Error).message}`))\n }\n }, this.pingIntervalMs)\n }\n\n private stopPingHeartbeat(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer)\n this.pingTimer = null\n }\n }\n\n private startSafetySync(): void {\n if (this.safetySyncTimer) return\n\n this.safetySyncTimer = setInterval(() => {\n if (!this.running) return\n\n void this.reconcileRecentEmails(20).catch((err) => {\n this.emit('error', new Error(`Safety reconcile failed: ${(err as Error).message}`))\n })\n }, this.safetySyncIntervalMs)\n }\n\n private async handleStateChange(stateChange: JmapStateChange): Promise<void> {\n if (!this.session) return\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n if (!accountId) return\n\n const changedAccount = stateChange.changed[accountId]\n if (!changedAccount?.Email) return\n\n try {\n if (this.emailState === null) {\n // State not yet initialized (race between open handler and first StateChange)\n // Just initialize and skip \u2014 next StateChange will use Email/changes properly\n await this.initEmailState(accountId)\n return\n }\n\n const emails = await this.fetchEmailsSince(accountId, this.emailState)\n for (const email of emails) {\n this.processEmail(email)\n }\n } catch (err) {\n this.emit('error', new Error(`Failed to fetch emails: ${(err as Error).message}`))\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null\n if (this.running) {\n await this.connect()\n }\n }, this.reconnectInterval)\n }\n\n isConnected(): boolean {\n return this.connected || this.pollingActive\n }\n\n isUsingPollingFallback(): boolean {\n return this.pollingActive && !this.connected\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearTimeout(this.pollTimer)\n this.pollTimer = null\n }\n this.pollingActive = false\n }\n\n private startPolling(reason: string): void {\n if (!this.running || this.pollingActive) return\n\n this.pollingActive = true\n this.emit('error', new Error(`JMAP WebSocket unavailable, falling back to polling: ${reason}`))\n this.emit('connected')\n\n const poll = async () => {\n if (!this.running || this.connected) {\n this.stopPolling()\n return\n }\n\n try {\n if (!this.session) {\n this.session = await this.fetchSession()\n }\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n ?? Object.keys(this.session.accounts)[0]\n\n if (!accountId) {\n throw new Error('No mail account available in JMAP session')\n }\n\n if (this.emailState === null) {\n const recentEmails = await this.fetchRecentEmails(accountId)\n for (const email of recentEmails.sort((a, b) => {\n const aTs = new Date(a.receivedAt).getTime()\n const bTs = new Date(b.receivedAt).getTime()\n return aTs - bTs\n })) {\n if (!this.shouldProcessBootstrapEmail(email)) continue\n this.processEmail(email)\n }\n await this.initEmailState(accountId)\n } else {\n const emails = await this.fetchEmailsSince(accountId, this.emailState)\n for (const email of emails) {\n this.processEmail(email)\n }\n }\n } catch (err) {\n this.emit('error', new Error(`Polling fallback failed: ${(err as Error).message}`))\n } finally {\n if (this.running && !this.connected) {\n this.pollTimer = setTimeout(poll, this.reconnectInterval)\n }\n }\n }\n\n this.pollTimer = setTimeout(poll, 0)\n }\n\n /**\n * Download a blob (attachment) by its JMAP blobId.\n * Returns the raw binary content as a Buffer.\n */\n async downloadBlob(blobId: string, filename?: string): Promise<Buffer> {\n if (!this.session) {\n // Fetch session on demand if not yet connected\n this.session = await this.fetchSession()\n }\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n ?? Object.keys(this.session.accounts)[0]\n\n // Build download URL from session template or fall back to standard JMAP path\n let downloadUrl = this.session.downloadUrl\n ?? `${this.jmapUrl}/jmap/download/{accountId}/{blobId}/{name}`\n\n // Replace session.downloadUrl host with our configured jmapUrl\n // (Stalwart may report an internal hostname unreachable from outside Docker)\n try {\n const parsed = new URL(downloadUrl)\n const configured = new URL(this.jmapUrl)\n parsed.protocol = configured.protocol\n parsed.host = configured.host\n downloadUrl = parsed.toString()\n } catch {\n // If URL parsing fails, use the template as-is\n }\n\n const safeFilename = filename ?? 'attachment'\n downloadUrl = downloadUrl\n .replace(/\\{accountId\\}|%7BaccountId%7D/gi, encodeURIComponent(accountId))\n .replace(/\\{blobId\\}|%7BblobId%7D/gi, encodeURIComponent(blobId))\n .replace(/\\{name\\}|%7Bname%7D/gi, encodeURIComponent(safeFilename))\n .replace(/\\{type\\}|%7Btype%7D/gi, 'application/octet-stream')\n\n // Retry with exponential backoff \u2014 the blob may not be immediately available\n // after the result email is observed (store/index write delay).\n const maxAttempts = 8\n let lastStatus: number | null = null\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const res = await fetch(downloadUrl, {\n headers: { Authorization: this.getAuthHeader() },\n })\n lastStatus = res.status\n if (res.ok) {\n const arrayBuffer = await res.arrayBuffer()\n return Buffer.from(arrayBuffer)\n }\n if (attempt < maxAttempts && (res.status === 404 || res.status === 429 || res.status === 503)) {\n console.warn(\n `[AAMP-SDK] blob download retry status=${res.status} attempt=${attempt}/${maxAttempts} url=${downloadUrl}`,\n )\n const delay = Math.min(1000 * Math.pow(2, attempt - 1), 15000) // 1s, 2s, 4s, 8s, 15s...\n await new Promise(r => setTimeout(r, delay))\n continue\n }\n console.error(\n `[AAMP-SDK] blob download failed status=${res.status} attempt=${attempt}/${maxAttempts} url=${downloadUrl}`,\n )\n throw new Error(\n `Blob download failed: status=${res.status} attempt=${attempt}/${maxAttempts} blobId=${blobId} filename=${filename ?? 'attachment'} url=${downloadUrl}`,\n )\n }\n throw new Error(\n `Blob download failed after retries: status=${lastStatus ?? 'unknown'} attempt=${maxAttempts}/${maxAttempts} blobId=${blobId} filename=${filename ?? 'attachment'} url=${downloadUrl}`,\n )\n }\n\n /**\n * Actively reconcile recent mailbox contents via JMAP HTTP.\n * Useful as a safety net when the WebSocket stays \"connected\"\n * but a notification is missed by an intermediate layer.\n */\n async reconcileRecentEmails(limit = 20): Promise<number> {\n if (!this.session) {\n this.session = await this.fetchSession()\n }\n\n const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']\n ?? Object.keys(this.session.accounts)[0]\n\n if (!accountId) {\n throw new Error('No mail account available in JMAP session')\n }\n\n const queryResp = await this.jmapCall([\n [\n 'Email/query',\n {\n accountId,\n sort: [{ property: 'receivedAt', isAscending: false }],\n limit,\n },\n 'qReconcile',\n ],\n ])\n\n const queryResult = queryResp.methodResponses.find(([name]) => name === 'Email/query')\n if (!queryResult) return 0\n\n const ids = ((queryResult[1] as { ids?: string[] }).ids ?? []).slice(0, limit)\n if (ids.length === 0) return 0\n\n const emailResp = await this.jmapCall([\n [\n 'Email/get',\n {\n accountId,\n ids,\n properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],\n fetchTextBodyValues: true,\n maxBodyValueBytes: 262144,\n },\n 'gReconcile',\n ],\n ])\n\n const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get')\n if (!getResult) return 0\n\n const emails = (getResult[1] as { list?: JmapEmail[] }).list ?? []\n for (const email of emails.sort((a, b) => {\n const aTs = new Date(a.receivedAt).getTime()\n const bTs = new Date(b.receivedAt).getTime()\n return aTs - bTs\n })) {\n if (!this.shouldProcessBootstrapEmail(email)) continue\n this.processEmail(email)\n }\n\n return emails.length\n }\n}\n", "/**\n * AAMP SDK Type Definitions\n */\n\nexport const AAMP_PROTOCOL_VERSION = '1.0'\n\nexport type AampIntent = 'task.dispatch' | 'task.result' | 'task.help_needed' | 'task.ack'\n\nexport type TaskStatus =\n | 'pending'\n | 'running'\n | 'completed'\n | 'rejected'\n | 'failed'\n | 'timeout'\n | 'help_needed'\n\n// =====================================================\n// AAMP Header constants\n// =====================================================\nexport const AAMP_HEADER = {\n VERSION: 'X-AAMP-Version',\n INTENT: 'X-AAMP-Intent',\n TASK_ID: 'X-AAMP-TaskId',\n TIMEOUT: 'X-AAMP-Timeout',\n CONTEXT_LINKS: 'X-AAMP-ContextLinks',\n DISPATCH_CONTEXT: 'X-AAMP-Dispatch-Context',\n STATUS: 'X-AAMP-Status',\n OUTPUT: 'X-AAMP-Output',\n ERROR_MSG: 'X-AAMP-ErrorMsg',\n STRUCTURED_RESULT: 'X-AAMP-StructuredResult',\n QUESTION: 'X-AAMP-Question',\n BLOCKED_REASON: 'X-AAMP-BlockedReason',\n SUGGESTED_OPTIONS: 'X-AAMP-SuggestedOptions',\n PARENT_TASK_ID: 'X-AAMP-ParentTaskId',\n} as const\n\nexport interface StructuredResultField {\n fieldKey: string\n fieldTypeKey: string\n value?: unknown\n fieldAlias?: string\n index?: string\n attachmentFilenames?: string[]\n}\n\n// =====================================================\n// Parsed AAMP headers for task.dispatch\n// =====================================================\nexport interface TaskDispatch {\n protocolVersion: string\n intent: 'task.dispatch'\n taskId: string\n title: string\n timeoutSecs: number\n contextLinks: string[]\n dispatchContext?: Record<string, string>\n parentTaskId?: string\n // Email metadata\n from: string\n to: string\n messageId: string\n subject: string\n /** Plain-text body of the email (task description) */\n bodyText: string\n /** Attachments received with this dispatch (use blobId to download) */\n attachments?: ReceivedAttachment[]\n}\n\n// =====================================================\n// Parsed AAMP headers for task.result\n// =====================================================\nexport interface TaskResult {\n protocolVersion: string\n intent: 'task.result'\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n structuredResult?: StructuredResultField[]\n from: string\n to: string\n messageId?: string\n /** True when the reply came from a standard email client (no X-AAMP-Intent header).\n * taskId was resolved via In-Reply-To \u2192 Message-ID reverse lookup. */\n isHumanReply?: boolean\n /** Attachments received with this result (use blobId to download) */\n attachments?: ReceivedAttachment[]\n}\n\n// =====================================================\n// Human reply via standard email client (no AAMP headers)\n// Emitted as 'reply' event when an email has In-Reply-To but no X-AAMP-Intent.\n// The application layer is responsible for resolving inReplyTo \u2192 taskId\n// (e.g. via Redis reverse index) and deciding how to handle it.\n// =====================================================\nexport interface HumanReply {\n /** Message-ID of the email being replied to \u2014 use this to look up the taskId */\n inReplyTo: string\n /** This reply email's own Message-ID */\n messageId: string\n from: string\n to: string\n subject: string\n /** Plain-text body of the reply */\n bodyText: string\n}\n\n// =====================================================\n// Parsed AAMP headers for task.help_needed\n// =====================================================\nexport interface TaskHelp {\n protocolVersion: string\n intent: 'task.help_needed'\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions: string[]\n from: string\n to: string\n messageId?: string\n}\n\n// =====================================================\n// Parsed AAMP headers for task.ack\n// =====================================================\nexport interface TaskAck {\n protocolVersion: string\n intent: 'task.ack'\n taskId: string\n from: string\n to: string\n messageId?: string\n}\n\n// =====================================================\n// Attachment types\n// =====================================================\n\n/** Attachment for sending (binary content) */\nexport interface AampAttachment {\n filename: string\n contentType: string\n content: Buffer | string // Buffer for binary, base64 string for REST API\n size?: number\n}\n\n/** Attachment metadata received via JMAP (use blobId to download) */\nexport interface ReceivedAttachment {\n filename: string\n contentType: string\n size: number\n blobId: string\n}\n\nexport type AampMessage = TaskDispatch | TaskResult | TaskHelp | TaskAck | HumanReply\n\n// =====================================================\n// SDK Configuration\n// =====================================================\nexport interface AampClientConfig {\n /** Node email address, e.g. codereviewer-abc123@aamp.yourdomain.com */\n email: string\n\n /** Base64(email:smtpPassword) \u2014 returned by management service on agent creation */\n jmapToken: string\n\n /** Stalwart base URL, e.g. http://localhost:8080 */\n jmapUrl: string\n\n /** Optional HTTP send base URL. Defaults to jmapUrl and is used for same-domain send fallback via /api/send. */\n httpSendBaseUrl?: string\n\n /** SMTP submission host */\n smtpHost: string\n\n /** SMTP submission port (default: 587) */\n smtpPort?: number\n\n /** SMTP password (returned by management service on agent creation) */\n smtpPassword: string\n\n /** How often to retry failed JMAP connection (ms, default: 5000) */\n reconnectInterval?: number\n\n /** Whether to reject unauthorized TLS certificates (default: true).\n * Set to false only for development with self-signed certificates. */\n rejectUnauthorized?: boolean\n}\n\n// =====================================================\n// Options for sending emails\n// =====================================================\nexport interface SendTaskOptions {\n /** Target node email */\n to: string\n title: string\n bodyText?: string\n timeoutSecs?: number\n contextLinks?: string[]\n dispatchContext?: Record<string, string>\n parentTaskId?: string\n /** Attachments to include with the dispatch email */\n attachments?: AampAttachment[]\n}\n\nexport interface SendResultOptions {\n /** Send to: the original from address of the dispatch email */\n to: string\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n structuredResult?: StructuredResultField[]\n /** Message-ID of the dispatch email, for In-Reply-To threading */\n inReplyTo?: string\n /** Attachments to include with the result email */\n attachments?: AampAttachment[]\n}\n\nexport interface SendHelpOptions {\n /** Send to: the original from address of the dispatch email */\n to: string\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions: string[]\n /** Message-ID of the dispatch email, for In-Reply-To threading */\n inReplyTo?: string\n /** Attachments to include with the help email */\n attachments?: AampAttachment[]\n}\n\n// =====================================================\n// Event emitter types\n// =====================================================\nexport interface AampClientEvents {\n 'task.dispatch': (task: TaskDispatch) => void\n 'task.result': (result: TaskResult) => void\n 'task.help_needed': (help: TaskHelp) => void\n /** @deprecated compatibility alias for task.help_needed */\n 'task.help': (help: TaskHelp) => void\n 'task.ack': (ack: TaskAck) => void\n /** Emitted when a standard email reply (no X-AAMP headers) is received for a known thread.\n * Use inReplyTo to look up the taskId in your own store (Redis / DB). */\n 'reply': (reply: HumanReply) => void\n connected: () => void\n disconnected: (reason: string) => void\n error: (err: Error) => void\n}\n", "/**\n * AAMP Header Parser\n *\n * Parses AAMP protocol headers from email messages.\n * Works with both raw header objects and JMAP Email objects.\n *\n * Headers are case-insensitive; we normalize to lowercase for lookup.\n */\n\nimport { AAMP_HEADER, AAMP_PROTOCOL_VERSION, type AampMessage, type TaskDispatch, type TaskResult, type TaskHelp, type TaskAck } from './types.js'\n\ntype RawHeaders = Record<string, string | string[]>\n\nfunction decodeMimeEncodedWordSegment(segment: string): string {\n const match = /^=\\?([^?]+)\\?([bBqQ])\\?([^?]*)\\?=$/.exec(segment)\n if (!match) return segment\n\n const [, charsetRaw, encodingRaw, body] = match\n const charset = charsetRaw.toLowerCase()\n const encoding = encodingRaw.toUpperCase()\n\n try {\n if (encoding === 'B') {\n const buf = Buffer.from(body, 'base64')\n return buf.toString(charset === 'utf-8' || charset === 'utf8' ? 'utf8' : 'utf8')\n }\n\n const normalized = body\n .replace(/_/g, ' ')\n .replace(/=([0-9A-Fa-f]{2})/g, (_, hex: string) =>\n String.fromCharCode(parseInt(hex, 16)),\n )\n const bytes = Buffer.from(normalized, 'binary')\n return bytes.toString(charset === 'utf-8' || charset === 'utf8' ? 'utf8' : 'utf8')\n } catch {\n return segment\n }\n}\n\nfunction decodeMimeEncodedWords(value?: string): string {\n if (!value || !value.includes('=?')) return value ?? ''\n const collapsed = value.replace(/\\r?\\n[ \\t]+/g, ' ')\n const decoded = collapsed.replace(/=\\?[^?]+\\?[bBqQ]\\?[^?]*\\?=/g, (segment) =>\n decodeMimeEncodedWordSegment(segment),\n )\n return decoded.replace(/\\s{2,}/g, ' ').trim()\n}\n\n/**\n * Normalize a header map to lowercase keys with string values\n */\nexport function normalizeHeaders(headers: RawHeaders): Record<string, string> {\n return Object.fromEntries(\n Object.entries(headers).map(([k, v]) => [\n k.toLowerCase(),\n Array.isArray(v) ? v[0] : v,\n ]),\n )\n}\n\n/**\n * Get a header value by its X-AAMP-* name (case-insensitive)\n */\nfunction getAampHeader(\n headers: Record<string, string>,\n headerName: string,\n): string | undefined {\n return headers[headerName.toLowerCase()]\n}\n\nconst DISPATCH_CONTEXT_KEY_RE = /^[a-z0-9_-]+$/\n\nexport function parseDispatchContextHeader(value?: string): Record<string, string> | undefined {\n if (!value) return undefined\n const context: Record<string, string> = {}\n\n for (const part of value.split(';')) {\n const segment = part.trim()\n if (!segment) continue\n const eqIdx = segment.indexOf('=')\n if (eqIdx <= 0) continue\n const rawKey = segment.slice(0, eqIdx).trim()\n const rawValue = segment.slice(eqIdx + 1).trim()\n if (!DISPATCH_CONTEXT_KEY_RE.test(rawKey)) continue\n try {\n context[rawKey] = decodeURIComponent(rawValue)\n } catch {\n context[rawKey] = rawValue\n }\n }\n\n return Object.keys(context).length ? context : undefined\n}\n\nexport function serializeDispatchContextHeader(context?: Record<string, string>): string | undefined {\n if (!context) return undefined\n const parts = Object.entries(context)\n .flatMap(([key, value]) => {\n const normalizedKey = key.trim().toLowerCase()\n if (!DISPATCH_CONTEXT_KEY_RE.test(normalizedKey)) return []\n const normalizedValue = String(value ?? '').trim()\n if (!normalizedValue) return []\n return `${normalizedKey}=${encodeURIComponent(normalizedValue)}`\n })\n return parts.length ? parts.join('; ') : undefined\n}\n\nfunction decodeStructuredResult(value?: string): TaskResult['structuredResult'] | undefined {\n if (!value) return undefined\n try {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/')\n const padding = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4))\n const decoded = Buffer.from(normalized + padding, 'base64').toString('utf-8')\n return JSON.parse(decoded) as TaskResult['structuredResult']\n } catch {\n return undefined\n }\n}\n\nfunction encodeStructuredResult(value?: TaskResult['structuredResult']): string | undefined {\n if (!value) return undefined\n const json = JSON.stringify(value)\n return Buffer.from(json, 'utf-8')\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/g, '')\n}\n\nexport interface EmailMetadata {\n from: string\n to: string\n messageId: string\n subject: string\n headers: RawHeaders\n}\n\n/**\n * Parse AAMP headers from an email's header map.\n * Returns null if this email is not an AAMP message.\n *\n * @param meta - Email metadata (from, to, messageId, subject, headers)\n */\nexport function parseAampHeaders(meta: EmailMetadata): AampMessage | null {\n const headers = normalizeHeaders(meta.headers)\n\n const intent = getAampHeader(headers, AAMP_HEADER.INTENT)\n const taskId = getAampHeader(headers, AAMP_HEADER.TASK_ID)\n const protocolVersion = getAampHeader(headers, AAMP_HEADER.VERSION) ?? AAMP_PROTOCOL_VERSION\n\n if (!intent || !taskId) return null\n\n const from = meta.from.replace(/^<|>$/g, '')\n const to = meta.to.replace(/^<|>$/g, '')\n const decodedSubject = decodeMimeEncodedWords(meta.subject)\n\n if (intent === 'task.dispatch') {\n const timeoutStr = getAampHeader(headers, AAMP_HEADER.TIMEOUT) ?? '300'\n const contextLinksStr = getAampHeader(headers, AAMP_HEADER.CONTEXT_LINKS) ?? ''\n const dispatchContext = parseDispatchContextHeader(\n getAampHeader(headers, AAMP_HEADER.DISPATCH_CONTEXT),\n )\n\n const parentTaskId = getAampHeader(headers, AAMP_HEADER.PARENT_TASK_ID)\n\n const dispatch: TaskDispatch = {\n protocolVersion,\n intent: 'task.dispatch',\n taskId,\n title: decodedSubject.replace(/^\\[AAMP Task\\]\\s*/, '').trim() || 'Untitled Task',\n timeoutSecs: parseInt(timeoutStr, 10) || 300,\n contextLinks: contextLinksStr\n ? contextLinksStr.split(',').map((s) => s.trim()).filter(Boolean)\n : [],\n ...(dispatchContext ? { dispatchContext } : {}),\n ...(parentTaskId ? { parentTaskId } : {}),\n from,\n to,\n messageId: meta.messageId,\n subject: meta.subject,\n bodyText: '', // filled in by jmap-push.ts after parsing\n }\n return dispatch\n }\n\n if (intent === 'task.result') {\n const status = (getAampHeader(headers, AAMP_HEADER.STATUS) ?? 'completed') as\n | 'completed'\n | 'rejected'\n const output = getAampHeader(headers, AAMP_HEADER.OUTPUT) ?? ''\n const errorMsg = getAampHeader(headers, AAMP_HEADER.ERROR_MSG)\n const structuredResult = decodeStructuredResult(\n getAampHeader(headers, AAMP_HEADER.STRUCTURED_RESULT),\n )\n\n const result: TaskResult = {\n protocolVersion,\n intent: 'task.result',\n taskId,\n status,\n output: decodeMimeEncodedWords(output),\n errorMsg: errorMsg ? decodeMimeEncodedWords(errorMsg) : errorMsg,\n structuredResult,\n from,\n to,\n messageId: meta.messageId,\n }\n return result\n }\n\n if (intent === 'task.help_needed' || intent === 'task.help') {\n const question = getAampHeader(headers, AAMP_HEADER.QUESTION) ?? ''\n const blockedReason = getAampHeader(headers, AAMP_HEADER.BLOCKED_REASON) ?? ''\n const suggestedOptionsStr = getAampHeader(headers, AAMP_HEADER.SUGGESTED_OPTIONS) ?? ''\n\n const help: TaskHelp = {\n protocolVersion,\n intent: 'task.help_needed',\n taskId,\n question: decodeMimeEncodedWords(question),\n blockedReason: decodeMimeEncodedWords(blockedReason),\n suggestedOptions: suggestedOptionsStr\n ? suggestedOptionsStr.split('|').map((s) => decodeMimeEncodedWords(s.trim())).filter(Boolean)\n : [],\n from,\n to,\n messageId: meta.messageId,\n }\n return help\n }\n\n if (intent === 'task.ack') {\n const ack: TaskAck = {\n protocolVersion,\n intent: 'task.ack',\n taskId,\n from,\n to,\n messageId: meta.messageId,\n }\n return ack\n }\n\n return null\n}\n\n/**\n * Build AAMP headers for a task.dispatch email\n */\nexport function buildDispatchHeaders(params: {\n taskId: string\n /** Omit or pass undefined/null to send without a deadline */\n timeoutSecs?: number | null\n contextLinks: string[]\n dispatchContext?: Record<string, string>\n parentTaskId?: string\n}): Record<string, string> {\n const headers: Record<string, string> = {\n [AAMP_HEADER.VERSION]: AAMP_PROTOCOL_VERSION,\n [AAMP_HEADER.INTENT]: 'task.dispatch',\n [AAMP_HEADER.TASK_ID]: params.taskId,\n }\n if (params.timeoutSecs != null) {\n headers[AAMP_HEADER.TIMEOUT] = String(params.timeoutSecs)\n }\n if (params.contextLinks.length > 0) {\n headers[AAMP_HEADER.CONTEXT_LINKS] = params.contextLinks.join(',')\n }\n const dispatchContext = serializeDispatchContextHeader(params.dispatchContext)\n if (dispatchContext) {\n headers[AAMP_HEADER.DISPATCH_CONTEXT] = dispatchContext\n }\n if (params.parentTaskId) {\n headers[AAMP_HEADER.PARENT_TASK_ID] = params.parentTaskId\n }\n return headers\n}\n\n/**\n * Build AAMP headers for a task.ack email\n */\nexport function buildAckHeaders(opts: { taskId: string }): Record<string, string> {\n return {\n [AAMP_HEADER.VERSION]: AAMP_PROTOCOL_VERSION,\n [AAMP_HEADER.INTENT]: 'task.ack',\n [AAMP_HEADER.TASK_ID]: opts.taskId,\n }\n}\n\n/**\n * Build AAMP headers for a task.result email\n */\nexport function buildResultHeaders(params: {\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n structuredResult?: TaskResult['structuredResult']\n}): Record<string, string> {\n const headers: Record<string, string> = {\n [AAMP_HEADER.VERSION]: AAMP_PROTOCOL_VERSION,\n [AAMP_HEADER.INTENT]: 'task.result',\n [AAMP_HEADER.TASK_ID]: params.taskId,\n [AAMP_HEADER.STATUS]: params.status,\n [AAMP_HEADER.OUTPUT]: params.output,\n }\n if (params.errorMsg) {\n headers[AAMP_HEADER.ERROR_MSG] = params.errorMsg\n }\n const structuredResult = encodeStructuredResult(params.structuredResult)\n if (structuredResult) {\n headers[AAMP_HEADER.STRUCTURED_RESULT] = structuredResult\n }\n return headers\n}\n\n/**\n * Build AAMP headers for a task.help_needed email\n */\nexport function buildHelpHeaders(params: {\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions: string[]\n}): Record<string, string> {\n return {\n [AAMP_HEADER.VERSION]: AAMP_PROTOCOL_VERSION,\n [AAMP_HEADER.INTENT]: 'task.help_needed',\n [AAMP_HEADER.TASK_ID]: params.taskId,\n [AAMP_HEADER.QUESTION]: params.question,\n [AAMP_HEADER.BLOCKED_REASON]: params.blockedReason,\n [AAMP_HEADER.SUGGESTED_OPTIONS]: params.suggestedOptions.join('|'),\n }\n}\n", "type Listener = (...args: unknown[]) => void\ntype EventListener<Events, K extends keyof Events> =\n Extract<Events[K], (...args: any[]) => void>\ntype EventArgs<Events, K extends keyof Events> =\n EventListener<Events, K> extends (...args: infer A) => void ? A : never\n\nexport class TinyEmitter<Events extends object> {\n private readonly listeners = new Map<keyof Events, Set<Listener>>()\n private readonly onceWrappers = new WeakMap<Listener, Listener>()\n\n on<K extends keyof Events>(event: K, listener: EventListener<Events, K>): this {\n const bucket = this.listeners.get(event) ?? new Set<Listener>()\n bucket.add(listener as Listener)\n this.listeners.set(event, bucket)\n return this\n }\n\n once<K extends keyof Events>(event: K, listener: EventListener<Events, K>): this {\n const wrapped: Listener = (...args: unknown[]) => {\n this.off(event, listener)\n ;(listener as Listener)(...args)\n }\n this.onceWrappers.set(listener as Listener, wrapped)\n return this.on(event, wrapped as EventListener<Events, K>)\n }\n\n off<K extends keyof Events>(event: K, listener: EventListener<Events, K>): this {\n const bucket = this.listeners.get(event)\n if (!bucket) return this\n\n const original = listener as Listener\n const wrapped = this.onceWrappers.get(original)\n bucket.delete(wrapped ?? original)\n if (wrapped) this.onceWrappers.delete(original)\n if (bucket.size === 0) this.listeners.delete(event)\n return this\n }\n\n protected emit<K extends keyof Events>(event: K, ...args: EventArgs<Events, K>): boolean {\n const bucket = this.listeners.get(event)\n if (!bucket || bucket.size === 0) return false\n\n for (const listener of [...bucket]) {\n listener(...args)\n }\n return true\n }\n}\n", "/**\n * SMTP Sender\n *\n * Sends AAMP protocol emails via SMTP (Stalwart submission port 587).\n */\n\nimport { createTransport, type Transporter } from 'nodemailer'\nimport { randomUUID } from 'crypto'\n\n/** Strip CR/LF to prevent email header injection */\nconst sanitize = (s: string) => s.replace(/[\\r\\n]/g, ' ').trim()\nimport { buildDispatchHeaders, buildResultHeaders, buildHelpHeaders, buildAckHeaders } from './parser.js'\nimport type {\n SendTaskOptions,\n SendResultOptions,\n SendHelpOptions,\n} from './types.js'\n\nexport interface SmtpConfig {\n host: string\n port: number\n user: string\n password: string\n httpBaseUrl?: string\n authToken?: string\n secure?: boolean\n /** Whether to reject unauthorized TLS certificates (default: true) */\n rejectUnauthorized?: boolean\n}\n\nexport class SmtpSender {\n private transport: Transporter\n\n constructor(private readonly config: SmtpConfig) {\n this.transport = createTransport({\n host: config.host,\n port: config.port,\n secure: config.secure ?? false,\n auth: {\n user: config.user,\n pass: config.password,\n },\n tls: {\n rejectUnauthorized: config.rejectUnauthorized ?? true,\n },\n })\n }\n\n private senderDomain(): string {\n return this.config.user.split('@')[1]?.toLowerCase() ?? ''\n }\n\n private recipientDomain(email: string): string {\n return email.split('@')[1]?.toLowerCase() ?? ''\n }\n\n private shouldUseHttpFallback(to: string): boolean {\n return Boolean(\n this.config.httpBaseUrl\n && this.config.authToken\n && this.senderDomain()\n && this.senderDomain() === this.recipientDomain(to),\n )\n }\n\n private async sendViaHttp(opts: {\n to: string\n subject: string\n text: string\n aampHeaders: Record<string, string>\n attachments?: Array<{ filename: string; contentType: string; content: Buffer | string }>\n }): Promise<{ messageId?: string }> {\n const base = this.config.httpBaseUrl?.replace(/\\/$/, '')\n if (!base || !this.config.authToken) {\n throw new Error('HTTP send fallback is not configured')\n }\n\n const res = await fetch(`${base}/api/send`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${this.config.authToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n to: opts.to,\n subject: opts.subject,\n text: opts.text,\n aampHeaders: opts.aampHeaders,\n attachments: opts.attachments?.map((a) => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? a.content : a.content.toString('base64'),\n })),\n }),\n })\n\n const data = await res.json().catch(() => ({})) as { details?: string; messageId?: string }\n if (!res.ok) {\n throw new Error(data.details || `HTTP send failed: ${res.status}`)\n }\n return { messageId: data.messageId }\n }\n\n /**\n * Send a task.dispatch email.\n * Returns both the generated taskId and the SMTP Message-ID so callers can\n * store a reverse-index (messageId \u2192 taskId) for In-Reply-To thread routing.\n */\n async sendTask(opts: SendTaskOptions): Promise<{ taskId: string; messageId: string }> {\n const taskId = randomUUID()\n const aampHeaders = buildDispatchHeaders({\n taskId,\n timeoutSecs: opts.timeoutSecs,\n contextLinks: opts.contextLinks ?? [],\n parentTaskId: opts.parentTaskId,\n })\n\n const sendMailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP Task] ${sanitize(opts.title)}`,\n text: [\n `Task: ${opts.title}`,\n `Task ID: ${taskId}`,\n opts.timeoutSecs ? `Deadline: ${opts.timeoutSecs}s` : `Deadline: none`,\n opts.contextLinks?.length\n ? `Context:\\n${opts.contextLinks.map((l) => ` ${l}`).join('\\n')}`\n : '',\n opts.bodyText ?? '',\n ``,\n `--- This email was sent by AAMP. Reply directly to submit your result. ---`,\n ]\n .filter(Boolean)\n .join('\\n'),\n headers: aampHeaders,\n }\n\n if (opts.attachments?.length) {\n sendMailOpts.attachments = opts.attachments.map(a => ({\n filename: a.filename,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n contentType: a.contentType,\n }))\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n const info = await this.sendViaHttp({\n to: opts.to,\n subject: sendMailOpts.subject as string,\n text: sendMailOpts.text as string,\n aampHeaders,\n attachments: opts.attachments?.map(a => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n })),\n })\n return { taskId, messageId: info.messageId ?? '' }\n }\n\n const info = await this.transport.sendMail(sendMailOpts)\n\n return { taskId, messageId: info.messageId ?? '' }\n }\n\n /**\n * Send a task.result email back to the dispatcher\n */\n async sendResult(opts: SendResultOptions): Promise<void> {\n const aampHeaders = buildResultHeaders({\n taskId: opts.taskId,\n status: opts.status,\n output: opts.output,\n errorMsg: opts.errorMsg,\n structuredResult: opts.structuredResult,\n })\n\n const mailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP Result] Task ${opts.taskId} \u2014 ${opts.status}`,\n text: [\n `AAMP Task Result`,\n ``,\n `Task ID: ${opts.taskId}`,\n `Status: ${opts.status}`,\n ``,\n `Output:`,\n opts.output,\n opts.errorMsg ? `\\nError: ${opts.errorMsg}` : '',\n ]\n .filter((s) => s !== '')\n .join('\\n'),\n headers: aampHeaders,\n }\n if (opts.inReplyTo) {\n mailOpts.inReplyTo = opts.inReplyTo\n mailOpts.references = opts.inReplyTo\n }\n if (opts.attachments?.length) {\n mailOpts.attachments = opts.attachments.map(a => ({\n filename: a.filename,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n contentType: a.contentType,\n }))\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n await this.sendViaHttp({\n to: opts.to,\n subject: mailOpts.subject as string,\n text: mailOpts.text as string,\n aampHeaders,\n attachments: opts.attachments?.map(a => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n })),\n })\n return\n }\n await this.transport.sendMail(mailOpts)\n }\n\n /**\n * Send a task.help email when the agent is blocked\n */\n async sendHelp(opts: SendHelpOptions): Promise<void> {\n const aampHeaders = buildHelpHeaders({\n taskId: opts.taskId,\n question: opts.question,\n blockedReason: opts.blockedReason,\n suggestedOptions: opts.suggestedOptions,\n })\n\n const helpMailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP Help] Task ${opts.taskId} needs assistance`,\n text: [\n `AAMP Task Help Request`,\n ``,\n `Task ID: ${opts.taskId}`,\n ``,\n `Question: ${opts.question}`,\n ``,\n `Blocked reason: ${opts.blockedReason}`,\n ``,\n opts.suggestedOptions.length\n ? `Suggested options:\\n${opts.suggestedOptions.map((o, i) => ` ${i + 1}. ${o}`).join('\\n')}`\n : '',\n ]\n .filter(Boolean)\n .join('\\n'),\n headers: aampHeaders,\n }\n if (opts.inReplyTo) {\n helpMailOpts.inReplyTo = opts.inReplyTo\n helpMailOpts.references = opts.inReplyTo\n }\n if (opts.attachments?.length) {\n helpMailOpts.attachments = opts.attachments.map(a => ({\n filename: a.filename,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n contentType: a.contentType,\n }))\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n await this.sendViaHttp({\n to: opts.to,\n subject: helpMailOpts.subject as string,\n text: helpMailOpts.text as string,\n aampHeaders,\n attachments: opts.attachments?.map(a => ({\n filename: a.filename,\n contentType: a.contentType,\n content: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,\n })),\n })\n return\n }\n await this.transport.sendMail(helpMailOpts)\n }\n\n /**\n * Send a task.ack email to confirm receipt of a dispatch\n */\n async sendAck(opts: { to: string; taskId: string; inReplyTo?: string }): Promise<void> {\n const aampHeaders = buildAckHeaders({ taskId: opts.taskId })\n const mailOpts: Record<string, unknown> = {\n from: this.config.user,\n to: opts.to,\n subject: `[AAMP ACK] Task ${opts.taskId}`,\n text: '',\n headers: aampHeaders,\n }\n if (opts.inReplyTo) {\n mailOpts.inReplyTo = opts.inReplyTo\n mailOpts.references = opts.inReplyTo\n }\n\n if (this.shouldUseHttpFallback(opts.to)) {\n await this.sendViaHttp({\n to: opts.to,\n subject: mailOpts.subject as string,\n text: mailOpts.text as string,\n aampHeaders,\n })\n return\n }\n await this.transport.sendMail(mailOpts)\n }\n\n /**\n * Verify SMTP connection\n */\n async verify(): Promise<boolean> {\n try {\n await this.transport.verify()\n return true\n } catch {\n return false\n }\n }\n\n close(): void {\n this.transport.close()\n }\n}\n", "/**\n * AampClient \u2014 Main SDK entry point\n *\n * Combines JMAP WebSocket Push (receive) + SMTP (send) into a single client.\n *\n * Usage:\n *\n * ```typescript\n * const client = new AampClient({\n * email: 'codereviewer-abc@aamp.example.com',\n * jmapToken: '<base64-token>',\n * jmapUrl: 'http://localhost:8080',\n * smtpHost: 'localhost',\n * smtpPort: 587,\n * smtpPassword: 'agent-smtp-password',\n * })\n *\n * // Listen for incoming tasks\n * client.on('task.dispatch', async (task) => {\n * const result = await doWork(task)\n * await client.sendResult({\n * to: task.from,\n * taskId: task.taskId,\n * status: 'completed',\n * output: result,\n * })\n * })\n *\n * await client.connect()\n * ```\n */\n\nimport { JmapPushClient } from './jmap-push.js'\nimport { SmtpSender } from './smtp-sender.js'\nimport { TinyEmitter } from './tiny-emitter.js'\nimport type {\n AampClientConfig,\n AampClientEvents,\n TaskDispatch,\n TaskResult,\n TaskHelp,\n TaskAck,\n HumanReply,\n SendTaskOptions,\n SendResultOptions,\n SendHelpOptions,\n} from './types.js'\n\nexport class AampClient extends TinyEmitter<AampClientEvents> {\n private jmapClient: JmapPushClient\n private smtpSender: SmtpSender\n private readonly config: AampClientConfig\n\n constructor(config: AampClientConfig) {\n super()\n this.config = config\n\n // Decode JMAP token (format: base64(email:password))\n let password: string\n try {\n const decoded = Buffer.from(config.jmapToken, 'base64').toString('utf-8')\n const colonIdx = decoded.indexOf(':')\n if (colonIdx < 0) throw new Error('Invalid jmapToken format: expected base64(email:password)')\n password = decoded.slice(colonIdx + 1)\n if (!password) throw new Error('Invalid jmapToken: empty password')\n } catch (err) {\n if (err instanceof Error && err.message.startsWith('Invalid jmapToken')) throw err\n throw new Error(`Failed to decode jmapToken: ${(err as Error).message}`)\n }\n\n this.jmapClient = new JmapPushClient({\n email: config.email,\n password: password ?? config.smtpPassword,\n jmapUrl: config.jmapUrl,\n reconnectInterval: config.reconnectInterval ?? 5000,\n rejectUnauthorized: config.rejectUnauthorized,\n })\n\n this.smtpSender = new SmtpSender({\n host: config.smtpHost,\n port: config.smtpPort ?? 587,\n user: config.email,\n password: config.smtpPassword,\n httpBaseUrl: config.httpSendBaseUrl ?? config.jmapUrl,\n authToken: config.jmapToken,\n rejectUnauthorized: config.rejectUnauthorized,\n })\n\n // Forward JMAP events to this emitter\n this.jmapClient.on('task.dispatch', (task: TaskDispatch) => {\n this.emit('task.dispatch', task)\n })\n\n this.jmapClient.on('task.result', (result: TaskResult) => {\n this.emit('task.result', result)\n })\n\n this.jmapClient.on('task.help_needed', (help: TaskHelp) => {\n this.emit('task.help_needed', help)\n this.emit('task.help', help)\n })\n\n this.jmapClient.on('task.ack', (ack: TaskAck) => {\n this.emit('task.ack', ack)\n })\n\n // Auto-ACK: when a task.dispatch is received, automatically send an ACK back\n this.jmapClient.on('_autoAck', async ({ to, taskId, messageId }: { to: string; taskId: string; messageId: string }) => {\n try {\n await this.smtpSender.sendAck({ to, taskId, inReplyTo: messageId })\n } catch (err) {\n console.warn(`[AAMP] Failed to send ACK for task ${taskId}: ${(err as Error).message}`)\n }\n })\n\n this.jmapClient.on('reply', (reply: HumanReply) => {\n this.emit('reply', reply)\n })\n\n this.jmapClient.on('connected', () => {\n this.emit('connected')\n })\n\n this.jmapClient.on('disconnected', (reason: string) => {\n this.emit('disconnected', reason)\n })\n\n this.jmapClient.on('error', (err: Error) => {\n this.emit('error', err)\n })\n }\n\n // =====================================================\n // Lifecycle\n // =====================================================\n\n /**\n * Connect to JMAP and start listening for tasks\n */\n async connect(): Promise<void> {\n await this.jmapClient.start()\n }\n\n /**\n * Disconnect and clean up\n */\n disconnect(): void {\n this.jmapClient.stop()\n this.smtpSender.close()\n }\n\n /**\n * Returns true if the JMAP connection is active\n */\n isConnected(): boolean {\n return this.jmapClient.isConnected()\n }\n\n isUsingPollingFallback(): boolean {\n return this.jmapClient.isUsingPollingFallback()\n }\n\n // =====================================================\n // Sending\n // =====================================================\n\n /**\n * Send a task.dispatch email to an agent.\n * Returns the generated taskId and the SMTP Message-ID.\n * Store messageId \u2192 taskId in Redis/DB to support In-Reply-To thread routing\n * for human replies that arrive without X-AAMP headers.\n */\n async sendTask(opts: SendTaskOptions): Promise<{ taskId: string; messageId: string }> {\n return this.smtpSender.sendTask(opts)\n }\n\n /**\n * Send a task.result email (agent \u2192 system/dispatcher)\n */\n async sendResult(opts: SendResultOptions): Promise<void> {\n return this.smtpSender.sendResult(opts)\n }\n\n /**\n * Send a task.help email when the agent needs human assistance\n */\n async sendHelp(opts: SendHelpOptions): Promise<void> {\n return this.smtpSender.sendHelp(opts)\n }\n\n /**\n * Download a blob (attachment) by its JMAP blobId.\n * Use this to retrieve attachment content from received TaskDispatch or TaskResult messages.\n * Returns the raw binary content as a Buffer.\n */\n async downloadBlob(blobId: string, filename?: string): Promise<Buffer> {\n return this.jmapClient.downloadBlob(blobId, filename)\n }\n\n /**\n * Reconcile recent mailbox contents via JMAP HTTP to catch messages missed by\n * a flaky WebSocket path. Safe to call periodically; duplicate processing is\n * suppressed by the JMAP push client.\n */\n async reconcileRecentEmails(limit?: number): Promise<number> {\n return this.jmapClient.reconcileRecentEmails(limit)\n }\n\n /**\n * Verify SMTP connectivity\n */\n async verifySmtp(): Promise<boolean> {\n return this.smtpSender.verify()\n }\n\n get email(): string {\n return this.config.email\n }\n}\n", "import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { homedir } from 'node:os'\n\nexport interface Identity {\n email: string\n jmapToken: string\n smtpPassword: string\n}\n\nexport function defaultCredentialsPath(): string {\n return join(homedir(), '.openclaw', 'extensions', 'aamp-openclaw-plugin', '.credentials.json')\n}\n\nexport function loadCachedIdentity(file?: string): Identity | null {\n const resolved = file ?? defaultCredentialsPath()\n if (!existsSync(resolved)) return null\n try {\n const parsed = JSON.parse(readFileSync(resolved, 'utf-8')) as Partial<Identity>\n if (!parsed.email || !parsed.jmapToken || !parsed.smtpPassword) return null\n return parsed as Identity\n } catch {\n return null\n }\n}\n\nexport function saveCachedIdentity(identity: Identity, file?: string): void {\n const resolved = file ?? defaultCredentialsPath()\n mkdirSync(dirname(resolved), { recursive: true })\n writeFileSync(resolved, JSON.stringify(identity, null, 2), 'utf-8')\n}\n\nexport function ensureDir(dir: string): void {\n mkdirSync(dir, { recursive: true })\n}\n\nexport function readBinaryFile(path: string): Buffer {\n return readFileSync(path)\n}\n\nexport function writeBinaryFile(path: string, content: Uint8Array | Buffer): void {\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, content)\n}\n", "/**\n * @aamp/openclaw-plugin\n *\n * OpenClaw plugin that gives the agent an AAMP mailbox identity and lets it\n * receive, process, and reply to AAMP tasks \u2014 entirely through standard email.\n *\n * How it works:\n * 1. Plugin resolves or auto-registers an AAMP mailbox identity on startup.\n * 2. Credentials are cached to a local file so the same mailbox is reused\n * across gateway restarts (no re-registration needed).\n * 3. Background JMAP WebSocket Push receives incoming task.dispatch emails.\n * 4. Incoming tasks are stored in an in-memory pending-task queue.\n * 5. before_prompt_build injects the oldest pending task into the LLM's\n * system context so the agent sees it and acts without user prompting.\n * 6. The agent calls aamp_send_result or aamp_send_help to reply.\n *\n * OpenClaw config (openclaw.json):\n *\n * \"plugins\": {\n * \"entries\": {\n * \"aamp\": {\n * \"enabled\": true,\n * \"config\": {\n * \"aampHost\": \"https://meshmail.ai\",\n * \"slug\": \"openclaw-agent\",\n * \"credentialsFile\": \"/absolute/path/to/.aamp-credentials.json\"\n * }\n * }\n * }\n * }\n *\n * Install:\n * openclaw plugins install ./packages/openclaw-plugin\n */\n\nimport { AampClient } from '../../sdk/src/index.ts'\nimport type {\n TaskDispatch,\n TaskResult,\n TaskHelp,\n AampAttachment,\n ReceivedAttachment,\n} from '../../sdk/src/types.ts'\nimport {\n defaultCredentialsPath,\n ensureDir,\n loadCachedIdentity,\n readBinaryFile,\n saveCachedIdentity,\n writeBinaryFile,\n type Identity,\n} from './file-store.js'\n\n// \u2500\u2500\u2500 Shared runtime state (single instance per plugin lifetime) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface PendingTask {\n taskId: string\n from: string\n title: string\n bodyText: string\n contextLinks: string[]\n timeoutSecs: number\n messageId: string\n receivedAt: string // ISO-8601\n}\n\ninterface PluginConfig {\n /** e.g. \"meshmail.ai\" \u2014 all URLs are derived from this */\n aampHost: string\n slug?: string\n /** Absolute path to cache AAMP credentials. Default: ~/.openclaw/extensions/aamp-openclaw-plugin/.credentials.json */\n credentialsFile?: string\n senderPolicies?: SenderPolicy[]\n}\n\ninterface SenderPolicy {\n sender: string\n dispatchContextRules?: Record<string, string[]>\n}\n\nfunction matchSenderPolicy(\n task: TaskDispatch,\n senderPolicies: SenderPolicy[] | undefined,\n): { allowed: boolean; reason?: string } {\n if (!senderPolicies?.length) return { allowed: true }\n\n const sender = task.from.toLowerCase()\n const policy = senderPolicies.find((item) => item.sender.trim().toLowerCase() === sender)\n if (!policy) {\n return { allowed: false, reason: `sender ${task.from} is not allowed by senderPolicies` }\n }\n\n const rules = policy.dispatchContextRules\n if (!rules || Object.keys(rules).length === 0) {\n return { allowed: true }\n }\n\n const context = task.dispatchContext ?? {}\n const effectiveRules = Object.entries(rules)\n .map(([key, allowedValues]) => [\n key,\n (allowedValues ?? []).map((value) => value.trim()).filter(Boolean),\n ] as const)\n .filter(([, allowedValues]) => allowedValues.length > 0)\n\n if (effectiveRules.length === 0) {\n return { allowed: true }\n }\n\n for (const [key, allowedValues] of effectiveRules) {\n const contextValue = context[key]\n if (!contextValue) {\n return { allowed: false, reason: `dispatchContext missing required key \"${key}\"` }\n }\n if (!allowedValues.includes(contextValue)) {\n return { allowed: false, reason: `dispatchContext ${key}=${contextValue} is not allowed` }\n }\n }\n\n return { allowed: true }\n}\n\ntype StructuredResultFieldInput = {\n fieldKey: string\n fieldTypeKey: string\n fieldAlias?: string\n value?: unknown\n index?: string\n attachmentFilenames?: string[]\n}\n\n/** Normalise aampHost to a base URL with scheme and no trailing slash */\nfunction baseUrl(aampHost: string): string {\n if (aampHost.startsWith('http://') || aampHost.startsWith('https://')) {\n return aampHost.replace(/\\/$/, '')\n }\n return `https://${aampHost}`\n}\n\nconst pendingTasks = new Map<string, PendingTask>()\n// Tracks sub-tasks dispatched TO other agents \u2014 waiting for their result/help replies\nconst dispatchedSubtasks = new Map<string, { to: string; title: string; dispatchedAt: string; parentTaskId?: string }>()\n// Tracks notification keys that have been shown to LLM (auto-cleaned on next prompt build)\nconst shownNotifications = new Set<string>()\n// Pending synchronous dispatch waiters \u2014 resolve callback keyed by sub-task ID.\n// When aamp_dispatch_task sends a sub-task, it parks a Promise here and waits.\n// When task.result/help arrives for that sub-task ID, the waiter is resolved\n// directly, keeping the LLM awake with full context (no heartbeat needed).\nconst waitingDispatches = new Map<string, (reply: { type: 'result' | 'help'; data: unknown }) => void>()\nlet aampClient: AampClient | null = null\nlet agentEmail = ''\nlet lastConnectionError = ''\nlet lastDisconnectReason = ''\nlet lastTransportMode: 'disconnected' | 'websocket' | 'polling' = 'disconnected'\nlet lastLoggedTransportMode: 'disconnected' | 'websocket' | 'polling' = 'disconnected'\nlet reconcileTimer: NodeJS.Timeout | null = null\nlet transportMonitorTimer: NodeJS.Timeout | null = null\n// Tracks the most recently seen session key so task.dispatch can wake the right session.\n// Default 'agent:main:main' is the standard OpenClaw single-agent session key.\nlet currentSessionKey = 'agent:main:main'\n// Channel runtime \u2014 captured from channel adapter's startAccount for instant dispatch.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet channelRuntime: any = null\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet channelCfg: any = null\n\nfunction logTransportState(\n api: { logger: { info: (msg: string) => void; warn: (msg: string) => void } },\n mode: 'websocket' | 'polling',\n email: string,\n previousMode: 'disconnected' | 'websocket' | 'polling',\n): void {\n if (mode === previousMode) return\n\n if (mode === 'polling') {\n api.logger.info(`[AAMP] Connected (polling fallback active) \u2014 listening as ${email}`)\n return\n }\n\n if (previousMode === 'polling') {\n api.logger.info(`[AAMP] WebSocket restored \u2014 listening as ${email}`)\n return\n }\n\n api.logger.info(`[AAMP] Connected \u2014 listening as ${email}`)\n}\n\n// \u2500\u2500\u2500 Identity helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface Identity {\n email: string\n jmapToken: string\n smtpPassword: string\n}\n\n/**\n * Register a new AAMP node via the management service.\n *\n * Always creates a NEW mailbox (always returns 201). The slug is just a\n * human-readable prefix; a random hex suffix makes the email unique.\n * Callers should only call this once and persist the returned credentials.\n */\nasync function registerNode(cfg: PluginConfig): Promise<Identity> {\n const slug = (cfg.slug ?? 'openclaw-agent')\n .toLowerCase()\n .replace(/[\\s_]+/g, '-')\n .replace(/[^a-z0-9-]/g, '')\n\n const base = baseUrl(cfg.aampHost)\n\n // Step 1: Self-register \u2192 get one-time registration code\n const res = await fetch(`${base}/api/nodes/self-register`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ slug, description: 'OpenClaw AAMP agent node' }),\n })\n\n if (!res.ok) {\n const err = (await res.json().catch(() => ({}))) as { error?: string }\n throw new Error(`AAMP registration failed (${res.status}): ${err.error ?? res.statusText}`)\n }\n\n const regData = (await res.json()) as {\n registrationCode: string\n email: string\n }\n\n // Step 2: Exchange registration code for credentials\n const credRes = await fetch(\n `${base}/api/nodes/credentials?code=${encodeURIComponent(regData.registrationCode)}`,\n )\n\n if (!credRes.ok) {\n const err = (await credRes.json().catch(() => ({}))) as { error?: string }\n throw new Error(`AAMP credential exchange failed (${credRes.status}): ${err.error ?? credRes.statusText}`)\n }\n\n const credData = (await credRes.json()) as {\n email: string\n jmap: { token: string }\n smtp: { password: string }\n }\n\n return {\n email: credData.email,\n jmapToken: credData.jmap.token,\n smtpPassword: credData.smtp.password,\n }\n}\n\n/**\n * Resolve this agent's identity:\n * 1. Return cached credentials from disk if available.\n * 2. Otherwise register a new node and cache the result.\n */\nasync function resolveIdentity(cfg: PluginConfig): Promise<Identity> {\n const cached = loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath())\n if (cached) return cached\n\n const identity = await registerNode(cfg)\n saveCachedIdentity(identity, cfg.credentialsFile ?? defaultCredentialsPath())\n return identity\n}\n\n// \u2500\u2500\u2500 Plugin definition \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default {\n id: 'aamp-openclaw-plugin',\n name: 'AAMP Agent Mail Protocol',\n\n configSchema: {\n type: 'object',\n properties: {\n aampHost: {\n type: 'string',\n description: 'AAMP service host, e.g. https://meshmail.ai',\n },\n slug: {\n type: 'string',\n default: 'openclaw-agent',\n description: 'Agent name prefix used in the mailbox address',\n },\n credentialsFile: {\n type: 'string',\n description:\n 'Absolute path to cache AAMP credentials between gateway restarts. ' +\n 'Default: ~/.openclaw/extensions/aamp-openclaw-plugin/.credentials.json. ' +\n 'Delete this file to force re-registration with a new mailbox.',\n },\n senderPolicies: {\n type: 'array',\n description:\n 'Per-sender authorization policies. Each sender can optionally require specific ' +\n 'X-AAMP-Dispatch-Context key/value pairs before a task is accepted.',\n items: {\n type: 'object',\n required: ['sender'],\n properties: {\n sender: {\n type: 'string',\n description: 'Dispatch sender email address (case-insensitive exact match).',\n },\n dispatchContextRules: {\n type: 'object',\n description:\n 'Optional exact-match rules over X-AAMP-Dispatch-Context. ' +\n 'All listed keys must be present and their values must match one of the configured entries.',\n additionalProperties: {\n type: 'array',\n items: { type: 'string' },\n },\n },\n },\n },\n },\n },\n },\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n register(api: any) {\n // OpenClaw channel plugins keep runtime config under channels.<channelId>.\n // Fall back to the legacy plugins.entries config so older installs still work.\n const cfg = ((api.config?.channels?.aamp ?? api.pluginConfig ?? {}) as PluginConfig)\n\n // \u2500\u2500 Register lightweight channel adapter to capture channelRuntime \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // We register as a channel SOLELY to get access to channelRuntime, which provides\n // dispatchReplyWithBufferedBlockDispatcher for instant LLM dispatch (bypassing\n // heartbeat's global running-mutex + requests-in-flight ~60s delay).\n // JMAP connection is managed by registerService, NOT startAccount.\n api.registerChannel({\n id: 'aamp',\n meta: { label: 'AAMP' },\n capabilities: { chatTypes: ['dm'] },\n config: {\n listAccountIds: () => cfg.aampHost ? ['default'] : [],\n resolveAccount: () => ({ aampHost: cfg.aampHost }),\n isEnabled: () => !!cfg.aampHost,\n isConfigured: () => !!loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath()),\n },\n gateway: {\n startAccount: async (ctx: { channelRuntime?: unknown; cfg?: unknown; abortSignal?: AbortSignal }) => {\n // Capture channelRuntime for use by sub-task notification dispatch\n channelRuntime = ctx.channelRuntime ?? null\n channelCfg = ctx.cfg ?? null\n api.logger.info(`[AAMP] Channel adapter started \u2014 channelRuntime ${channelRuntime ? 'available' : 'NOT available'}`)\n\n // Keep alive until abort \u2014 JMAP connection is managed by registerService\n await new Promise<void>((resolve) => {\n ctx.abortSignal?.addEventListener('abort', () => resolve())\n })\n channelRuntime = null\n channelCfg = null\n },\n stopAccount: async () => {\n channelRuntime = null\n channelCfg = null\n },\n },\n })\n\n function triggerHeartbeatWake(sessionKey: string, label: string): void {\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey })\n api.logger.info(`[AAMP] Heartbeat triggered for ${label} via session ${sessionKey}`)\n } catch (err) {\n api.logger.warn(`[AAMP] Could not trigger heartbeat for ${label}: ${(err as Error).message}`)\n }\n }\n\n function wakeAgentForPendingTask(task: PendingTask): void {\n const fallback = () => triggerHeartbeatWake(currentSessionKey, `task ${task.taskId}`)\n const dispatcher = channelRuntime?.reply?.dispatchReplyWithBufferedBlockDispatcher\n\n api.logger.info(\n `[AAMP] Wake requested for task ${task.taskId} \u2014 channelRuntime=${channelRuntime ? 'yes' : 'no'} channelCfg=${channelCfg ? 'yes' : 'no'} dispatcher=${typeof dispatcher === 'function' ? 'yes' : 'no'} session=${currentSessionKey}`,\n )\n\n if (!channelRuntime || !channelCfg || typeof dispatcher !== 'function') {\n fallback()\n return\n }\n\n const prompt = [\n '## New AAMP Task',\n '',\n 'A new AAMP task just arrived.',\n 'Use the pending AAMP task in system context as the source of truth and handle it now.',\n 'Reply with aamp_send_result or aamp_send_help before responding.',\n ].join('\\n')\n\n try {\n void Promise.resolve(dispatcher({\n ctx: {\n Body: task.bodyText || task.title,\n BodyForAgent: prompt,\n From: task.from,\n To: agentEmail,\n SessionKey: `aamp:default:task:${task.taskId}`,\n AccountId: 'default',\n ChatType: 'dm',\n Provider: 'aamp',\n Surface: 'aamp',\n OriginatingChannel: 'aamp',\n OriginatingTo: task.from,\n MessageSid: task.messageId || task.taskId,\n Timestamp: Date.now(),\n SenderName: task.from,\n SenderId: task.from,\n CommandAuthorized: true,\n },\n cfg: channelCfg,\n dispatcherOptions: {\n deliver: async () => {},\n onError: (err: unknown) => {\n api.logger.error(`[AAMP] Channel dispatch error for task ${task.taskId}: ${err instanceof Error ? err.message : String(err)}`)\n },\n },\n })).then(() => {\n api.logger.info(`[AAMP] Channel dispatch triggered for task ${task.taskId}`)\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Channel dispatch failed for task ${task.taskId}: ${err.message}`)\n fallback()\n })\n } catch (err) {\n api.logger.error(`[AAMP] Channel dispatch threw synchronously for task ${task.taskId}: ${(err as Error).message}`)\n fallback()\n }\n }\n\n // \u2500\u2500 Shared connect logic (used by service auto-connect and startup recovery) \u2500\u2500\u2500\u2500\u2500\u2500\n async function doConnect(identity: { email: string; jmapToken: string; smtpPassword: string }) {\n if (reconcileTimer) {\n clearInterval(reconcileTimer)\n reconcileTimer = null\n }\n if (transportMonitorTimer) {\n clearInterval(transportMonitorTimer)\n transportMonitorTimer = null\n }\n\n agentEmail = identity.email\n lastConnectionError = ''\n lastDisconnectReason = ''\n lastTransportMode = 'disconnected'\n lastLoggedTransportMode = 'disconnected'\n api.logger.info(`[AAMP] Mailbox identity ready \u2014 ${agentEmail}`)\n\n // All traffic goes through aampHost (port 3000).\n // The management service proxies /jmap/* and /.well-known/jmap \u2192 Stalwart:8080.\n const base = baseUrl(cfg.aampHost)\n\n aampClient = new AampClient({\n email: identity.email,\n jmapToken: identity.jmapToken,\n jmapUrl: base,\n smtpHost: new URL(base).hostname,\n smtpPort: 587,\n smtpPassword: identity.smtpPassword,\n // Local/dev: management-service proxy uses plain HTTP, no TLS cert to verify.\n // Production: set to true when using wss:// with valid certs.\n rejectUnauthorized: false,\n })\n\n aampClient.on('task.dispatch', (task: TaskDispatch) => {\n api.logger.info(`[AAMP] \u2190 task.dispatch ${task.taskId} \"${task.title}\" from=${task.from}`)\n\n try {\n // \u2500\u2500 Sender policy / dispatch-context authorization \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const decision = matchSenderPolicy(task, cfg.senderPolicies)\n if (!decision.allowed) {\n api.logger.warn(`[AAMP] \u2717 rejected by senderPolicies: ${task.from} task=${task.taskId} reason=${decision.reason}`)\n void aampClient!.sendResult({\n to: task.from,\n taskId: task.taskId,\n status: 'rejected',\n output: '',\n errorMsg: decision.reason ?? `Sender ${task.from} is not allowed.`,\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Failed to send rejection for task ${task.taskId}: ${err.message}`)\n })\n return\n }\n\n pendingTasks.set(task.taskId, {\n taskId: task.taskId,\n from: task.from,\n title: task.title,\n bodyText: task.bodyText ?? '',\n contextLinks: task.contextLinks,\n timeoutSecs: task.timeoutSecs,\n messageId: task.messageId ?? '',\n receivedAt: new Date().toISOString(),\n })\n\n // Wake the agent immediately after enqueueing the task.\n // In polling fallback mode heartbeat wakes can be delayed, so prefer a direct\n // channel dispatch when channelRuntime is available and only fall back to heartbeat.\n wakeAgentForPendingTask(pendingTasks.get(task.taskId)!)\n } catch (err) {\n api.logger.error(`[AAMP] task.dispatch handler failed for ${task.taskId}: ${(err as Error).message}`)\n if (pendingTasks.has(task.taskId)) {\n triggerHeartbeatWake(currentSessionKey, `task ${task.taskId}`)\n }\n }\n })\n\n // \u2500\u2500 Sub-task result: another agent completed a task we dispatched \u2500\u2500\u2500\u2500\u2500\u2500\n aampClient.on('task.result', (result: TaskResult) => {\n api.logger.info(`[AAMP] \u2190 task.result ${result.taskId} status=${result.status} from=${result.from}`)\n\n const sub = dispatchedSubtasks.get(result.taskId)\n dispatchedSubtasks.delete(result.taskId)\n\n // \u2500\u2500 Synchronous dispatch: if aamp_dispatch_task is waiting, resolve it directly \u2500\u2500\n const waiter = waitingDispatches.get(result.taskId)\n if (waiter) {\n waitingDispatches.delete(result.taskId)\n api.logger.info(`[AAMP] Resolving sync waiter for sub-task ${result.taskId}`)\n waiter({ type: 'result', data: result })\n return // Don't go through heartbeat/channel \u2014 the LLM is already awake\n }\n\n // Pre-download attachments to local disk so the LLM can reference them\n // by local file path (instead of requiring a separate download tool call).\n const downloadedFiles: Array<{ filename: string; path: string; size: number }> = []\n const downloadPromise = (async () => {\n if (!result.attachments?.length) return\n const dir = '/tmp/aamp-files'\n ensureDir(dir)\n for (const att of result.attachments) {\n try {\n const buffer = await aampClient!.downloadBlob(att.blobId, att.filename)\n const filepath = `${dir}/${att.filename}`\n writeBinaryFile(filepath, buffer)\n downloadedFiles.push({ filename: att.filename, path: filepath, size: buffer.length })\n api.logger.info(`[AAMP] Pre-downloaded: ${att.filename} (${(buffer.length / 1024).toFixed(1)} KB) \u2192 ${filepath}`)\n } catch (dlErr) {\n api.logger.warn(`[AAMP] Pre-download failed for ${att.filename}: ${(dlErr as Error).message}`)\n }\n }\n })()\n\n downloadPromise.then(() => {\n // Build notification with pre-downloaded file paths\n const MAX_OUTPUT_CHARS = 800\n const label = result.status === 'completed' ? 'Sub-task completed' : 'Sub-task rejected'\n const rawOutput = result.output ?? ''\n const truncatedOutput = rawOutput.length > MAX_OUTPUT_CHARS\n ? rawOutput.slice(0, MAX_OUTPUT_CHARS) + `\\n\\n... [truncated, ${rawOutput.length} chars total]`\n : rawOutput\n\n let attachmentInfo = ''\n if (downloadedFiles.length > 0) {\n attachmentInfo = `\\n\\nAttachments (pre-downloaded to local disk):\\n${downloadedFiles.map(f =>\n `- ${f.filename} (${(f.size / 1024).toFixed(1)} KB) \u2192 ${f.path}`\n ).join('\\n')}\\nUse aamp_send_result with attachments: [${downloadedFiles.map(f => `{ filename: \"${f.filename}\", path: \"${f.path}\" }`).join(', ')}] to forward them.`\n } else if (result.attachments?.length) {\n const files = result.attachments.map((a: ReceivedAttachment) =>\n `${a.filename} (${(a.size / 1024).toFixed(1)} KB, blobId: ${a.blobId})`,\n )\n attachmentInfo = `\\n\\nAttachments (download failed \u2014 use aamp_download_attachment manually):\\n${files.join('\\n')}`\n }\n\n pendingTasks.set(`result:${result.taskId}`, {\n taskId: result.taskId,\n from: result.from,\n title: `${label}: ${sub?.title ?? result.taskId}`,\n bodyText: result.status === 'completed'\n ? `Agent ${result.from} completed the sub-task.\\n\\nOutput:\\n${truncatedOutput}${attachmentInfo}`\n : `Agent ${result.from} rejected the sub-task.\\n\\nReason: ${result.errorMsg ?? 'unknown'}`,\n contextLinks: [],\n timeoutSecs: 0,\n messageId: '',\n receivedAt: new Date().toISOString(),\n })\n\n // Wake LLM via channel dispatch (instant) or heartbeat (fallback)\n if (channelRuntime && channelCfg) {\n const notifyBody = pendingTasks.get(`result:${result.taskId}`)\n const actionableTasks = [...pendingTasks.entries()]\n .filter(([key]) => !key.startsWith('result:') && !key.startsWith('help:'))\n .map(([, t]) => t)\n const actionSection = actionableTasks.length > 0\n ? `\\n\\n### Action Required\\nYou MUST call aamp_send_result to complete the pending task(s):\\n${actionableTasks.map(t => `- Task ID: ${t.taskId} | From: ${t.from} | Title: \"${t.title}\"`).join('\\n')}`\n : ''\n const prompt = `## Sub-task Update\\n\\n${notifyBody?.bodyText ?? 'Sub-task completed.'}${actionSection}`\n\n channelRuntime.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: {\n Body: `Sub-task result: ${result.taskId}`,\n BodyForAgent: prompt,\n From: result.from,\n To: agentEmail,\n SessionKey: `aamp:default:${result.from}`,\n AccountId: 'default',\n ChatType: 'dm',\n Provider: 'aamp',\n Surface: 'aamp',\n OriginatingChannel: 'aamp',\n OriginatingTo: result.from,\n MessageSid: result.taskId,\n Timestamp: Date.now(),\n SenderName: result.from,\n SenderId: result.from,\n CommandAuthorized: true,\n },\n cfg: channelCfg,\n dispatcherOptions: {\n deliver: async () => {},\n onError: (err: unknown) => {\n api.logger.error(`[AAMP] Channel dispatch error: ${err instanceof Error ? err.message : String(err)}`)\n },\n },\n }).then(() => {\n api.logger.info(`[AAMP] Channel dispatch completed for sub-task result ${result.taskId}`)\n pendingTasks.delete(`result:${result.taskId}`)\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Channel dispatch failed: ${err.message}`)\n })\n } else {\n const notifySessionKey = `agent:main:aamp-notify-${Date.now()}`\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: notifySessionKey })\n api.logger.info(`[AAMP] Heartbeat for sub-task result ${result.taskId}`)\n } catch (err) {\n api.logger.warn(`[AAMP] Heartbeat for sub-task result failed: ${(err as Error).message}`)\n }\n }\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Sub-task result processing failed: ${err.message}`)\n })\n })\n\n // \u2500\u2500 Sub-task help_needed: another agent asks for clarification \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n aampClient.on('task.help_needed', (help: TaskHelp) => {\n api.logger.info(`[AAMP] \u2190 task.help_needed ${help.taskId} question=\"${help.question}\" from=${help.from}`)\n\n // \u2500\u2500 Synchronous dispatch: if aamp_dispatch_task is waiting, resolve it directly \u2500\u2500\n const waiter = waitingDispatches.get(help.taskId)\n if (waiter) {\n waitingDispatches.delete(help.taskId)\n api.logger.info(`[AAMP] Resolving sync waiter for sub-task help ${help.taskId}`)\n waiter({ type: 'help', data: help })\n return\n }\n\n const sub = dispatchedSubtasks.get(help.taskId)\n\n pendingTasks.set(`help:${help.taskId}`, {\n taskId: help.taskId,\n from: help.from,\n title: `Sub-task needs help: ${sub?.title ?? help.taskId}`,\n bodyText: `Agent ${help.from} is asking for help on the sub-task.\\n\\nQuestion: ${help.question}\\nBlocked reason: ${help.blockedReason}${help.suggestedOptions?.length ? `\\nSuggested options: ${help.suggestedOptions.join(', ')}` : ''}`,\n contextLinks: [],\n timeoutSecs: 0,\n messageId: '',\n receivedAt: new Date().toISOString(),\n })\n\n if (channelRuntime && channelCfg) {\n const notifyBody = pendingTasks.get(`help:${help.taskId}`)\n const prompt = `## Sub-task Help Request\\n\\n${notifyBody?.bodyText ?? help.question}`\n\n channelRuntime.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: {\n Body: `Sub-task help: ${help.taskId}`,\n BodyForAgent: prompt,\n From: help.from,\n To: agentEmail,\n SessionKey: `aamp:default:${help.from}`,\n AccountId: 'default',\n ChatType: 'dm',\n Provider: 'aamp',\n Surface: 'aamp',\n OriginatingChannel: 'aamp',\n OriginatingTo: help.from,\n MessageSid: help.taskId,\n Timestamp: Date.now(),\n SenderName: help.from,\n SenderId: help.from,\n CommandAuthorized: true,\n },\n cfg: channelCfg,\n dispatcherOptions: {\n deliver: async () => {},\n onError: (err: unknown) => {\n api.logger.error(`[AAMP] Channel dispatch error (help): ${err instanceof Error ? err.message : String(err)}`)\n },\n },\n }).then(() => {\n pendingTasks.delete(`help:${help.taskId}`)\n }).catch((err: Error) => {\n api.logger.error(`[AAMP] Channel dispatch failed for help: ${err.message}`)\n })\n } else {\n const helpSessionKey = `agent:main:aamp-notify-${Date.now()}`\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: helpSessionKey })\n api.logger.info(`[AAMP] Heartbeat fallback for sub-task help ${help.taskId}`)\n } catch (err) {\n api.logger.warn(`[AAMP] Heartbeat for sub-task help failed: ${(err as Error).message}`)\n }\n }\n })\n\n aampClient.on('connected', () => {\n lastConnectionError = ''\n lastDisconnectReason = ''\n const mode = aampClient?.isUsingPollingFallback() ? 'polling' : 'websocket'\n logTransportState(api, mode, agentEmail, lastLoggedTransportMode)\n lastTransportMode = mode\n lastLoggedTransportMode = mode\n })\n\n aampClient.on('disconnected', (reason: string) => {\n lastDisconnectReason = reason\n if (lastTransportMode !== 'disconnected') {\n api.logger.warn(`[AAMP] Disconnected: ${reason} (will auto-reconnect)`)\n lastTransportMode = 'disconnected'\n lastLoggedTransportMode = 'disconnected'\n }\n })\n\n aampClient.on('error', (err: Error) => {\n lastConnectionError = err.message\n if (err.message.startsWith('JMAP WebSocket unavailable, falling back to polling:')) {\n if (lastTransportMode !== 'polling') {\n logTransportState(api, 'polling', agentEmail, lastLoggedTransportMode)\n lastTransportMode = 'polling'\n lastLoggedTransportMode = 'polling'\n }\n return\n }\n api.logger.error(`[AAMP] ${err.message}`)\n })\n\n await aampClient.connect()\n\n api.logger.info(\n `[AAMP] Transport after connect \u2014 ${aampClient.isUsingPollingFallback() ? 'polling fallback' : 'websocket'} as ${agentEmail}`,\n )\n\n if (aampClient.isConnected() && lastTransportMode === 'disconnected') {\n if (aampClient.isUsingPollingFallback()) {\n logTransportState(api, 'polling', agentEmail, lastLoggedTransportMode)\n lastTransportMode = 'polling'\n lastLoggedTransportMode = 'polling'\n } else {\n logTransportState(api, 'websocket', agentEmail, lastLoggedTransportMode)\n lastTransportMode = 'websocket'\n lastLoggedTransportMode = 'websocket'\n }\n }\n\n setTimeout(() => {\n if (!aampClient?.isConnected()) return\n const mode = aampClient.isUsingPollingFallback() ? 'polling' : 'websocket'\n logTransportState(api, mode, agentEmail, lastLoggedTransportMode)\n lastTransportMode = mode\n lastLoggedTransportMode = mode\n }, 1000)\n\n transportMonitorTimer = setInterval(() => {\n if (!aampClient) return\n if (!aampClient.isConnected()) {\n if (lastTransportMode !== 'disconnected') {\n lastTransportMode = 'disconnected'\n }\n return\n }\n const mode = aampClient.isUsingPollingFallback() ? 'polling' : 'websocket'\n logTransportState(api, mode, agentEmail, lastLoggedTransportMode)\n lastTransportMode = mode\n lastLoggedTransportMode = mode\n }, 5000)\n\n reconcileTimer = setInterval(() => {\n if (!aampClient) return\n void aampClient.reconcileRecentEmails(20).catch((err: Error) => {\n lastConnectionError = err.message\n api.logger.warn(`[AAMP] Mailbox reconcile failed: ${err.message}`)\n })\n }, 15000)\n }\n\n // \u2500\u2500 Service: auto-connect at gateway startup, disconnect on shutdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // registerService causes this plugin to load eagerly (at gateway startup),\n // not lazily (on first agent run). start() is called once the gateway is up.\n api.registerService({\n id: 'aamp-service',\n start: async () => {\n if (!cfg.aampHost) {\n api.logger.info('[AAMP] aampHost not configured \u2014 skipping auto-connect')\n return\n }\n try {\n const identity = await resolveIdentity(cfg)\n await doConnect(identity)\n } catch (err) {\n api.logger.warn(`[AAMP] Service auto-connect failed: ${(err as Error).message}`)\n }\n },\n stop: () => {\n if (reconcileTimer) {\n clearInterval(reconcileTimer)\n reconcileTimer = null\n }\n if (transportMonitorTimer) {\n clearInterval(transportMonitorTimer)\n transportMonitorTimer = null\n }\n if (aampClient) {\n try {\n aampClient.disconnect()\n api.logger.info('[AAMP] Disconnected on gateway stop')\n } catch {\n // ignore disconnect errors on shutdown\n }\n }\n },\n })\n\n // \u2500\u2500 gateway_start hook: re-trigger heartbeat after runner is initialized \u2500\u2500\u2500\n // Service start() runs BEFORE the heartbeat runner is ready, so\n // requestHeartbeatNow() called during JMAP initial fetch is silently dropped\n // (handler == null). gateway_start fires AFTER the heartbeat runner starts,\n // so we re-trigger here to process any tasks queued during startup.\n api.on('gateway_start', () => {\n if (pendingTasks.size === 0) return\n api.logger.info(`[AAMP] gateway_start: re-triggering heartbeat for ${pendingTasks.size} pending task(s)`)\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: currentSessionKey })\n } catch (err) {\n api.logger.warn(`[AAMP] gateway_start heartbeat failed: ${(err as Error).message}`)\n }\n })\n\n // \u2500\u2500 2. Prompt injection: surface the oldest pending task to the LLM \u2500\u2500\u2500\u2500\u2500\u2500\n api.on(\n 'before_prompt_build',\n (_event, ctx) => {\n // Keep currentSessionKey fresh \u2014 used by task.dispatch to target the right session.\n // Skip channel dispatch sessions (aamp:*) to avoid polluting the heartbeat session key.\n if (ctx?.sessionKey && !String(ctx.sessionKey).startsWith('aamp:')) {\n currentSessionKey = ctx.sessionKey\n }\n\n // Expire tasks that have exceeded their timeout\n const now = Date.now()\n for (const [id, t] of pendingTasks) {\n if (t.timeoutSecs && now - new Date(t.receivedAt).getTime() > t.timeoutSecs * 1000) {\n api.logger.warn(`[AAMP] Task ${id} timed out \u2014 removing from queue`)\n pendingTasks.delete(id)\n }\n }\n\n if (pendingTasks.size === 0) return {}\n\n // Prioritize notifications (sub-task results/help) over actionable tasks.\n // Without this, the oldest actionable task blocks notification delivery,\n // preventing the LLM from seeing sub-task results and completing the parent task.\n const allEntries = [...pendingTasks.entries()]\n const notifications = allEntries.filter(([key]) => key.startsWith('result:') || key.startsWith('help:'))\n const actionable = allEntries.filter(([key]) => !key.startsWith('result:') && !key.startsWith('help:'))\n\n // Pick notification first if available, otherwise oldest actionable task\n const [taskKey, task] = notifications.length > 0\n ? notifications.sort((a, b) => new Date(a[1].receivedAt).getTime() - new Date(b[1].receivedAt).getTime())[0]\n : actionable.sort((a, b) => new Date(a[1].receivedAt).getTime() - new Date(b[1].receivedAt).getTime())[0]\n\n const isNotification = taskKey.startsWith('result:') || taskKey.startsWith('help:')\n\n // Notifications are one-shot: remove immediately after injecting into prompt\n if (isNotification && taskKey) {\n pendingTasks.delete(taskKey)\n }\n\n // Find remaining actionable tasks (non-notification) that still need a response\n const actionableTasks = [...pendingTasks.entries()]\n .filter(([key]) => !key.startsWith('result:') && !key.startsWith('help:'))\n .map(([, t]) => t)\n\n const hasAttachmentInfo = isNotification && (task.bodyText?.includes('aamp_download_attachment') ?? false)\n const actionRequiredSection = isNotification && actionableTasks.length > 0\n ? [\n ``,\n `### Action Required`,\n ``,\n `You still have ${actionableTasks.length} pending task(s) that need a response.`,\n `Use the sub-task result above to complete them by calling aamp_send_result.`,\n ``,\n ...actionableTasks.map((t) =>\n `- Task ID: ${t.taskId} | From: ${t.from} | Title: \"${t.title}\"`\n ),\n ...(hasAttachmentInfo ? [\n ``,\n `### Forwarding Attachments`,\n `The sub-task result includes file attachments. To forward them:`,\n `1. Call aamp_download_attachment for each blobId listed above`,\n `2. Include the downloaded files in aamp_send_result via the attachments parameter`,\n ` Example: attachments: [{ filename: \"file.html\", path: \"/tmp/aamp-files/file.html\" }]`,\n ] : []),\n ].join('\\n')\n : ''\n\n const lines = isNotification ? [\n `## Sub-task Update`,\n ``,\n `A sub-task you dispatched has returned a result. Review the information below.`,\n `If the sub-task included attachments, use aamp_download_attachment to fetch them.`,\n ``,\n `Task ID: ${task.taskId}`,\n `From: ${task.from}`,\n `Title: ${task.title}`,\n task.bodyText ? `\\n${task.bodyText}` : '',\n actionRequiredSection,\n pendingTasks.size > 1 ? `\\n(+${pendingTasks.size - 1} more items queued)` : '',\n ] : [\n `## Pending AAMP Task (action required)`,\n ``,\n `You have received a task via AAMP email. You MUST call one of the two tools below`,\n `BEFORE responding to the user \u2014 do not skip this step.`,\n ``,\n `### Tool selection rules (follow strictly):`,\n ``,\n `Use aamp_send_result ONLY when ALL of the following are true:`,\n ` 1. The title contains a clear, specific action verb (e.g. \"summarise\", \"review\",`,\n ` \"translate\", \"generate\", \"fix\", \"search\", \"compare\", \"list\")`,\n ` 2. You know exactly what input/resource to act on`,\n ` 3. No ambiguity remains \u2014 you could start work immediately without asking anything`,\n ``,\n `Use aamp_send_help in ALL other cases, including:`,\n ` - Title is a greeting or salutation (\"hello\", \"hi\", \"hey\", \"test\", \"ping\", etc.)`,\n ` - Title is fewer than 4 words and contains no actionable verb`,\n ` - Title is too vague to act on without guessing (e.g. \"help\", \"task\", \"question\")`,\n ` - Required context is missing (which file? which URL? which criteria?)`,\n ` - Multiple interpretations are equally plausible`,\n ``,\n `IMPORTANT: Responding to a greeting with a greeting is WRONG. \"hello\" is not a`,\n `valid task description \u2014 ask what specific task the dispatcher needs done.`,\n ``,\n `### Sub-task dispatch rules:`,\n `If you delegate work to another agent via aamp_dispatch_task, you MUST pass`,\n `parentTaskId: \"${task.taskId}\" to establish the parent-child relationship.`,\n ``,\n `Task ID: ${task.taskId}`,\n `From: ${task.from}`,\n `Title: ${task.title}`,\n task.bodyText ? `Description:\\n${task.bodyText}` : '',\n task.contextLinks.length\n ? `Context Links:\\n${task.contextLinks.map((l) => ` - ${l}`).join('\\n')}`\n : '',\n task.timeoutSecs ? `Deadline: ${task.timeoutSecs}s from dispatch` : `Deadline: none`,\n `Received: ${task.receivedAt}`,\n pendingTasks.size > 1 ? `\\n(+${pendingTasks.size - 1} more tasks queued)` : '',\n ]\n .filter(Boolean)\n .join('\\n')\n\n return { prependContext: lines }\n },\n { priority: 5 },\n )\n\n // \u2500\u2500 3. Tool: send task result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_send_result',\n description:\n 'Send the result of an AAMP task back to the dispatcher. ' +\n 'Call this after you have finished processing the task.',\n parameters: {\n type: 'object',\n required: ['taskId', 'status', 'output'],\n properties: {\n taskId: {\n type: 'string',\n description: 'The AAMP task ID to reply to (from the system context)',\n },\n status: {\n type: 'string',\n enum: ['completed', 'rejected'],\n description: '\"completed\" on success, \"rejected\" if the task cannot be done',\n },\n output: {\n type: 'string',\n description: 'Your result or explanation',\n },\n errorMsg: {\n type: 'string',\n description: 'Optional error details (use only when status = rejected)',\n },\n attachments: {\n type: 'array',\n description: 'File attachments. Each item: { filename, contentType, path (local file path) }',\n items: {\n type: 'object',\n properties: {\n filename: { type: 'string' },\n contentType: { type: 'string' },\n path: { type: 'string', description: 'Absolute path to the file on disk' },\n },\n required: ['filename', 'path'],\n },\n },\n structuredResult: {\n type: 'array',\n description: 'Optional structured Meego field values.',\n items: {\n type: 'object',\n required: ['fieldKey', 'fieldTypeKey'],\n properties: {\n fieldKey: { type: 'string' },\n fieldTypeKey: { type: 'string' },\n fieldAlias: { type: 'string' },\n value: {\n description: 'Field value in the exact format required by Meego for this field type.',\n },\n index: { type: 'string' },\n attachmentFilenames: {\n type: 'array',\n items: { type: 'string' },\n description: 'For attachment fields, filenames from attachments[] that should be uploaded into this field.',\n },\n },\n },\n },\n },\n },\n execute: async (_id, params) => {\n const p = params as {\n taskId: string\n status: 'completed' | 'rejected'\n output: string\n errorMsg?: string\n attachments?: Array<{ filename: string; contentType?: string; path: string }>\n structuredResult?: StructuredResultFieldInput[]\n }\n\n const task = pendingTasks.get(p.taskId)\n if (!task) {\n return {\n content: [{ type: 'text', text: `Error: task ${p.taskId} not found in pending queue.` }],\n }\n }\n\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n api.logger.info(`[AAMP] aamp_send_result params ${JSON.stringify({\n taskId: p.taskId,\n status: p.status,\n output: p.output,\n errorMsg: p.errorMsg,\n attachments: p.attachments?.map((a) => ({\n filename: a.filename,\n contentType: a.contentType ?? 'application/octet-stream',\n path: a.path,\n })) ?? [],\n structuredResult: p.structuredResult?.map((field) => ({\n fieldKey: field.fieldKey,\n fieldTypeKey: field.fieldTypeKey,\n fieldAlias: field.fieldAlias,\n value: field.value,\n index: field.index,\n attachmentFilenames: field.attachmentFilenames ?? [],\n })) ?? [],\n })}`)\n\n // Build attachments from file paths\n let attachments: AampAttachment[] | undefined\n if (p.attachments?.length) {\n attachments = p.attachments.map((a: { filename: string; contentType?: string; path: string }) => ({\n filename: a.filename,\n contentType: a.contentType ?? 'application/octet-stream',\n content: readBinaryFile(a.path),\n }))\n }\n\n await aampClient.sendResult({\n to: task.from,\n taskId: task.taskId,\n status: p.status,\n output: p.output,\n errorMsg: p.errorMsg,\n structuredResult: p.structuredResult?.length ? p.structuredResult : undefined,\n inReplyTo: task.messageId || undefined,\n attachments,\n })\n\n pendingTasks.delete(task.taskId)\n api.logger.info(`[AAMP] \u2192 task.result ${task.taskId} ${p.status}`)\n\n // If more tasks remain, wake the agent to process them\n if (pendingTasks.size > 0) {\n try {\n api.runtime.system.requestHeartbeatNow({ reason: 'wake', sessionKey: currentSessionKey })\n } catch { /* ignore */ }\n }\n\n return {\n content: [\n {\n type: 'text',\n text: `Result sent for task ${task.taskId} (status: ${p.status}).`,\n },\n ],\n }\n },\n }, { name: 'aamp_send_result' })\n\n // \u2500\u2500 4. Tool: ask for help \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_send_help',\n description:\n 'Send a help request for an AAMP task when you are blocked or need human clarification ' +\n 'before you can proceed.',\n parameters: {\n type: 'object',\n required: ['taskId', 'question', 'blockedReason'],\n properties: {\n taskId: {\n type: 'string',\n description: 'The AAMP task ID',\n },\n question: {\n type: 'string',\n description: 'Your question for the human dispatcher',\n },\n blockedReason: {\n type: 'string',\n description: 'Why you cannot proceed without their input',\n },\n suggestedOptions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional list of choices for the dispatcher to pick from',\n },\n },\n },\n execute: async (_id, params) => {\n const p = params as {\n taskId: string\n question: string\n blockedReason: string\n suggestedOptions?: string[]\n }\n\n const task = pendingTasks.get(p.taskId)\n if (!task) {\n return {\n content: [{ type: 'text', text: `Error: task ${p.taskId} not found in pending queue.` }],\n }\n }\n\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n await aampClient.sendHelp({\n to: task.from,\n taskId: task.taskId,\n question: p.question,\n blockedReason: p.blockedReason,\n suggestedOptions: p.suggestedOptions ?? [],\n inReplyTo: task.messageId || undefined,\n })\n\n api.logger.info(`[AAMP] \u2192 task.help_needed ${task.taskId}`)\n\n // Keep the task in pending \u2014 the help reply may arrive later\n return {\n content: [\n {\n type: 'text',\n text: `Help request sent for task ${task.taskId}. The task remains pending until the dispatcher replies.`,\n },\n ],\n }\n },\n }, { name: 'aamp_send_help' })\n\n // \u2500\u2500 5. Tool: inspect queue \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_pending_tasks',\n description: 'List all AAMP tasks currently waiting to be processed.',\n parameters: { type: 'object', properties: {} },\n execute: async () => {\n if (pendingTasks.size === 0) {\n return { content: [{ type: 'text', text: 'No pending AAMP tasks.' }] }\n }\n\n const lines = [...pendingTasks.values()]\n .sort((a, b) => new Date(a.receivedAt).getTime() - new Date(b.receivedAt).getTime())\n .map(\n (t, i) =>\n `${i + 1}. [${t.taskId}] \"${t.title}\"${t.bodyText ? `\\n Description: ${t.bodyText}` : ''} \u2014 from ${t.from} (received ${t.receivedAt})`,\n )\n\n return {\n content: [\n {\n type: 'text',\n text: `${pendingTasks.size} pending task(s):\\n${lines.join('\\n')}`,\n },\n ],\n }\n },\n }, { name: 'aamp_pending_tasks' })\n\n // \u2500\u2500 6. Tool: dispatch task to another agent (SYNCHRONOUS) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Sends the task and BLOCKS until the sub-agent replies with task.result or\n // task.help. The reply is returned directly as the tool result, keeping the\n // LLM awake with full context \u2014 no heartbeat/channel dispatch needed.\n api.registerTool({\n name: 'aamp_dispatch_task',\n description:\n 'Send a task to another AAMP agent and WAIT for the result. ' +\n 'This tool blocks until the sub-agent replies (typically 5-60s). ' +\n 'The sub-agent\\'s output and any attachment file paths are returned directly.',\n parameters: {\n type: 'object',\n required: ['to', 'title'],\n properties: {\n to: { type: 'string', description: 'Target agent AAMP email address' },\n title: { type: 'string', description: 'Task title (concise summary)' },\n bodyText: { type: 'string', description: 'Detailed task description' },\n parentTaskId: { type: 'string', description: 'If you are processing a pending AAMP task, pass its Task ID here to establish parent-child nesting. Omit for top-level tasks.' },\n timeoutSecs: { type: 'number', description: 'Timeout in seconds (optional)' },\n contextLinks: {\n type: 'array', items: { type: 'string' },\n description: 'URLs providing context (optional)',\n },\n attachments: {\n type: 'array',\n description: 'File attachments. Each item: { filename, contentType, path (local file path) }',\n items: {\n type: 'object',\n properties: {\n filename: { type: 'string' },\n contentType: { type: 'string' },\n path: { type: 'string', description: 'Absolute path to the file on disk' },\n },\n required: ['filename', 'path'],\n },\n },\n },\n },\n execute: async (_id: unknown, params: {\n to: string; title: string; bodyText?: string;\n parentTaskId?: string; timeoutSecs?: number; contextLinks?: string[];\n attachments?: Array<{ filename: string; contentType?: string; path: string }>\n }) => {\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n try {\n // Build attachments from file paths\n let attachments: AampAttachment[] | undefined\n if (params.attachments?.length) {\n attachments = params.attachments.map((a: { filename: string; contentType?: string; path: string }) => ({\n filename: a.filename,\n contentType: a.contentType ?? 'application/octet-stream',\n content: readBinaryFile(a.path),\n }))\n }\n\n const result = await aampClient.sendTask({\n to: params.to,\n title: params.title,\n parentTaskId: params.parentTaskId,\n timeoutSecs: params.timeoutSecs,\n contextLinks: params.contextLinks,\n attachments,\n })\n\n // Track as dispatched sub-task\n dispatchedSubtasks.set(result.taskId, {\n to: params.to,\n title: params.title,\n dispatchedAt: new Date().toISOString(),\n parentTaskId: params.parentTaskId,\n })\n\n api.logger.info(`[AAMP] \u2192 task.dispatch ${result.taskId} to=${params.to} parent=${params.parentTaskId ?? 'none'} (waiting for reply\u2026)`)\n\n // \u2500\u2500 SYNCHRONOUS WAIT: block until sub-agent replies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const timeoutMs = (params.timeoutSecs ?? 300) * 1000\n const reply = await new Promise<{ type: 'result' | 'help'; data: unknown }>((resolve, reject) => {\n waitingDispatches.set(result.taskId, resolve)\n setTimeout(() => {\n if (waitingDispatches.delete(result.taskId)) {\n reject(new Error(`Sub-task ${result.taskId} timed out after ${params.timeoutSecs ?? 300}s`))\n }\n }, timeoutMs)\n })\n\n api.logger.info(`[AAMP] \u2190 sync reply for ${result.taskId}: type=${reply.type} attachments=${JSON.stringify((reply.data as any)?.attachments?.length ?? 0)}`)\n\n if (reply.type === 'result') {\n const r = reply.data as TaskResult\n\n // Pre-download attachments \u2014 use direct JMAP blob download (bypass SDK's downloadBlob\n // which was returning 404 due to URL construction issues in the esbuild bundle).\n let attachmentLines = ''\n if (r.attachments?.length) {\n api.logger.info(`[AAMP] Downloading ${r.attachments.length} attachment(s) from sync reply...`)\n const dir = '/tmp/aamp-files'\n ensureDir(dir)\n const downloaded: string[] = []\n const base = baseUrl(cfg.aampHost)\n const identity = loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath())\n const authHeader = identity ? `Basic ${Buffer.from(identity.email + ':' + identity.smtpPassword).toString('base64')}` : ''\n for (const att of r.attachments) {\n try {\n // Direct JMAP blob download \u2014 construct URL manually\n const dlUrl = `${base}/jmap/download/n/${encodeURIComponent(att.blobId)}/${encodeURIComponent(att.filename)}?accept=application/octet-stream`\n api.logger.info(`[AAMP] Fetching ${dlUrl}`)\n const dlRes = await fetch(dlUrl, { headers: { Authorization: authHeader } })\n if (!dlRes.ok) throw new Error(`HTTP ${dlRes.status}`)\n const buffer = Buffer.from(await dlRes.arrayBuffer())\n const filepath = `${dir}/${att.filename}`\n writeBinaryFile(filepath, buffer)\n downloaded.push(`${att.filename} (${(buffer.length / 1024).toFixed(1)} KB) \u2192 ${filepath}`)\n api.logger.info(`[AAMP] Downloaded: ${att.filename} (${(buffer.length / 1024).toFixed(1)} KB)`)\n } catch (dlErr) {\n api.logger.error(`[AAMP] Download failed for ${att.filename}: ${(dlErr as Error).message}`)\n }\n }\n if (downloaded.length) {\n attachmentLines = `\\n\\nAttachments downloaded:\\n${downloaded.join('\\n')}`\n }\n }\n\n return {\n content: [{\n type: 'text',\n text: [\n `Sub-task ${r.status}: ${params.title}`,\n `Agent: ${r.from}`,\n `Task ID: ${result.taskId}`,\n r.status === 'completed' ? `\\nOutput:\\n${r.output}` : `\\nError: ${r.errorMsg ?? 'rejected'}`,\n attachmentLines,\n ].filter(Boolean).join('\\n'),\n }],\n }\n } else {\n const h = reply.data as TaskHelp\n return {\n content: [{\n type: 'text',\n text: [\n `Sub-task needs help: ${params.title}`,\n `Agent: ${h.from}`,\n `Task ID: ${result.taskId}`,\n `\\nQuestion: ${h.question}`,\n `Blocked reason: ${h.blockedReason}`,\n h.suggestedOptions?.length ? `Options: ${h.suggestedOptions.join(' | ')}` : '',\n ].filter(Boolean).join('\\n'),\n }],\n }\n }\n } catch (err) {\n return {\n content: [{ type: 'text', text: `Error dispatching task: ${(err as Error).message}` }],\n }\n }\n },\n }, { name: 'aamp_dispatch_task' })\n\n // \u2500\u2500 7. Tool: check AAMP protocol support \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_check_protocol',\n description:\n 'Check if an email address supports the AAMP protocol. ' +\n 'Returns { aamp: true/false } indicating whether the address is an AAMP agent.',\n parameters: {\n type: 'object',\n required: ['email'],\n properties: {\n email: { type: 'string', description: 'Email address to check' },\n },\n },\n execute: async (_id: unknown, params: { email: string }) => {\n const base = baseUrl(cfg.aampHost)\n const email = params?.email ?? ''\n if (!email) {\n return { content: [{ type: 'text', text: 'Error: email parameter is required' }] }\n }\n try {\n const discoveryRes = await fetch(`${base}/.well-known/aamp`)\n if (!discoveryRes.ok) throw new Error(`HTTP ${discoveryRes.status}`)\n const discovery = await discoveryRes.json() as { api?: { url?: string } }\n const apiUrl = discovery.api?.url\n if (!apiUrl) throw new Error('AAMP discovery did not return api.url')\n const res = await fetch(`${base}${apiUrl}?action=aamp.mailbox.check&email=${encodeURIComponent(email)}`)\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json() as { aamp: boolean; domain?: string }\n return {\n content: [{\n type: 'text',\n text: data.aamp\n ? `${params.email} supports AAMP protocol (domain: ${data.domain ?? 'unknown'})`\n : `${params.email} does not support AAMP protocol`,\n }],\n }\n } catch (err) {\n return {\n content: [{ type: 'text', text: `Could not check ${params.email}: ${(err as Error).message}` }],\n }\n }\n },\n }, { name: 'aamp_check_protocol' })\n\n // \u2500\u2500 8. Tool: download attachment blob \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerTool({\n name: 'aamp_download_attachment',\n description:\n 'Download an AAMP email attachment to local disk by its blobId. ' +\n 'Use this to retrieve files received from sub-agent task results.',\n parameters: {\n type: 'object',\n required: ['blobId', 'filename'],\n properties: {\n blobId: { type: 'string', description: 'The JMAP blobId from the attachment metadata' },\n filename: { type: 'string', description: 'Filename to save as' },\n saveTo: { type: 'string', description: 'Directory to save to (default: /tmp/aamp-files)' },\n },\n },\n execute: async (_id: unknown, params: { blobId: string; filename: string; saveTo?: string }) => {\n if (!aampClient?.isConnected()) {\n return { content: [{ type: 'text', text: 'Error: AAMP client is not connected.' }] }\n }\n\n const dir = params.saveTo ?? '/tmp/aamp-files'\n ensureDir(dir)\n\n try {\n const buffer = await aampClient.downloadBlob(params.blobId, params.filename)\n const filepath = `${dir}/${params.filename}`\n writeBinaryFile(filepath, buffer)\n return {\n content: [{\n type: 'text',\n text: `Downloaded ${params.filename} (${(buffer.length / 1024).toFixed(1)} KB) to ${filepath}`,\n }],\n }\n } catch (err) {\n return {\n content: [{ type: 'text', text: `Download failed: ${(err as Error).message}` }],\n }\n }\n },\n }, { name: 'aamp_download_attachment' })\n\n // \u2500\u2500 9. Slash command: /aamp-status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n api.registerCommand({\n name: 'aamp-status',\n description: 'Show AAMP connection status and pending task queue',\n acceptsArgs: false,\n requireAuth: false,\n handler: () => {\n const isPollingFallback = aampClient?.isUsingPollingFallback?.() ?? false\n const connectionLine = aampClient?.isConnected()\n ? (isPollingFallback ? '\uD83D\uDFE1 connected (polling fallback)' : '\u2705 connected')\n : '\u274C disconnected'\n\n return {\n text: [\n `**AAMP Plugin Status**`,\n `Host: ${cfg.aampHost || '(not configured)'}`,\n `Identity: ${agentEmail || '(not yet registered)'}`,\n `Connection: ${connectionLine}`,\n `Cached: ${loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath()) ? 'yes' : 'no'}`,\n lastConnectionError ? `Last error: ${lastConnectionError}` : '',\n lastDisconnectReason ? `Last disconnect: ${lastDisconnectReason}` : '',\n `Pending: ${pendingTasks.size} task(s)`,\n ...[...pendingTasks.values()].map(\n (t) => ` \u2022 ${t.taskId.slice(0, 8)}\u2026 \"${t.title}\" from ${t.from}`,\n ),\n ]\n .filter(Boolean)\n .join('\\n'),\n }\n },\n })\n },\n}\n"],
|
|
5
|
+
"mappings": ";AAWA,OAAO,eAAe;;;ACPf,IAAM,wBAAwB;AAgB9B,IAAM,cAAc;AAAA,EACzB,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,mBAAmB;AAAA,EACnB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,gBAAgB;AAClB;;;ACtBA,SAAS,6BAA6B,SAAyB;AAC7D,QAAM,QAAQ,qCAAqC,KAAK,OAAO;AAC/D,MAAI,CAAC;AAAO,WAAO;AAEnB,QAAM,CAAC,EAAE,YAAY,aAAa,IAAI,IAAI;AAC1C,QAAM,UAAU,WAAW,YAAY;AACvC,QAAM,WAAW,YAAY,YAAY;AAEzC,MAAI;AACF,QAAI,aAAa,KAAK;AACpB,YAAM,MAAM,OAAO,KAAK,MAAM,QAAQ;AACtC,aAAO,IAAI,SAAS,YAAY,WAAW,YAAY,SAAS,SAAS,MAAM;AAAA,IACjF;AAEA,UAAM,aAAa,KAChB,QAAQ,MAAM,GAAG,EACjB;AAAA,MAAQ;AAAA,MAAsB,CAAC,GAAG,QACjC,OAAO,aAAa,SAAS,KAAK,EAAE,CAAC;AAAA,IACvC;AACF,UAAM,QAAQ,OAAO,KAAK,YAAY,QAAQ;AAC9C,WAAO,MAAM,SAAS,YAAY,WAAW,YAAY,SAAS,SAAS,MAAM;AAAA,EACnF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBAAuB,OAAwB;AACtD,MAAI,CAAC,SAAS,CAAC,MAAM,SAAS,IAAI;AAAG,WAAO,SAAS;AACrD,QAAM,YAAY,MAAM,QAAQ,gBAAgB,GAAG;AACnD,QAAM,UAAU,UAAU;AAAA,IAAQ;AAAA,IAA+B,CAAC,YAChE,6BAA6B,OAAO;AAAA,EACtC;AACA,SAAO,QAAQ,QAAQ,WAAW,GAAG,EAAE,KAAK;AAC9C;AAKO,SAAS,iBAAiB,SAA6C;AAC5E,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,OAAO,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM;AAAA,MACtC,EAAE,YAAY;AAAA,MACd,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI;AAAA,IAC5B,CAAC;AAAA,EACH;AACF;AAKA,SAAS,cACP,SACA,YACoB;AACpB,SAAO,QAAQ,WAAW,YAAY,CAAC;AACzC;AAEA,IAAM,0BAA0B;AAEzB,SAAS,2BAA2B,OAAoD;AAC7F,MAAI,CAAC;AAAO,WAAO;AACnB,QAAM,UAAkC,CAAC;AAEzC,aAAW,QAAQ,MAAM,MAAM,GAAG,GAAG;AACnC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC;AAAS;AACd,UAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,QAAI,SAAS;AAAG;AAChB,UAAM,SAAS,QAAQ,MAAM,GAAG,KAAK,EAAE,KAAK;AAC5C,UAAM,WAAW,QAAQ,MAAM,QAAQ,CAAC,EAAE,KAAK;AAC/C,QAAI,CAAC,wBAAwB,KAAK,MAAM;AAAG;AAC3C,QAAI;AACF,cAAQ,MAAM,IAAI,mBAAmB,QAAQ;AAAA,IAC/C,QAAQ;AACN,cAAQ,MAAM,IAAI;AAAA,IACpB;AAAA,EACF;AAEA,SAAO,OAAO,KAAK,OAAO,EAAE,SAAS,UAAU;AACjD;AAEO,SAAS,+BAA+B,SAAsD;AACnG,MAAI,CAAC;AAAS,WAAO;AACrB,QAAM,QAAQ,OAAO,QAAQ,OAAO,EACjC,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACzB,UAAM,gBAAgB,IAAI,KAAK,EAAE,YAAY;AAC7C,QAAI,CAAC,wBAAwB,KAAK,aAAa;AAAG,aAAO,CAAC;AAC1D,UAAM,kBAAkB,OAAO,SAAS,EAAE,EAAE,KAAK;AACjD,QAAI,CAAC;AAAiB,aAAO,CAAC;AAC9B,WAAO,GAAG,aAAa,IAAI,mBAAmB,eAAe,CAAC;AAAA,EAChE,CAAC;AACH,SAAO,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI;AAC3C;AAEA,SAAS,uBAAuB,OAA4D;AAC1F,MAAI,CAAC;AAAO,WAAO;AACnB,MAAI;AACF,UAAM,aAAa,MAAM,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AAC7D,UAAM,UAAU,WAAW,SAAS,MAAM,IAAI,KAAK,IAAI,OAAO,IAAK,WAAW,SAAS,CAAE;AACzF,UAAM,UAAU,OAAO,KAAK,aAAa,SAAS,QAAQ,EAAE,SAAS,OAAO;AAC5E,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBAAuB,OAA4D;AAC1F,MAAI,CAAC;AAAO,WAAO;AACnB,QAAM,OAAO,KAAK,UAAU,KAAK;AACjC,SAAO,OAAO,KAAK,MAAM,OAAO,EAC7B,SAAS,QAAQ,EACjB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,QAAQ,EAAE;AACvB;AAgBO,SAAS,iBAAiB,MAAyC;AACxE,QAAM,UAAU,iBAAiB,KAAK,OAAO;AAE7C,QAAM,SAAS,cAAc,SAAS,YAAY,MAAM;AACxD,QAAM,SAAS,cAAc,SAAS,YAAY,OAAO;AACzD,QAAM,kBAAkB,cAAc,SAAS,YAAY,OAAO,KAAK;AAEvE,MAAI,CAAC,UAAU,CAAC;AAAQ,WAAO;AAE/B,QAAM,OAAO,KAAK,KAAK,QAAQ,UAAU,EAAE;AAC3C,QAAM,KAAK,KAAK,GAAG,QAAQ,UAAU,EAAE;AACvC,QAAM,iBAAiB,uBAAuB,KAAK,OAAO;AAE1D,MAAI,WAAW,iBAAiB;AAC9B,UAAM,aAAa,cAAc,SAAS,YAAY,OAAO,KAAK;AAClE,UAAM,kBAAkB,cAAc,SAAS,YAAY,aAAa,KAAK;AAC7E,UAAM,kBAAkB;AAAA,MACtB,cAAc,SAAS,YAAY,gBAAgB;AAAA,IACrD;AAEA,UAAM,eAAe,cAAc,SAAS,YAAY,cAAc;AAEtE,UAAM,WAAyB;AAAA,MAC7B;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA,OAAO,eAAe,QAAQ,qBAAqB,EAAE,EAAE,KAAK,KAAK;AAAA,MACjE,aAAa,SAAS,YAAY,EAAE,KAAK;AAAA,MACzC,cAAc,kBACV,gBAAgB,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,IAC9D,CAAC;AAAA,MACL,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,MAC7C,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,MACvC;AAAA,MACA;AAAA,MACA,WAAW,KAAK;AAAA,MAChB,SAAS,KAAK;AAAA,MACd,UAAU;AAAA;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,eAAe;AAC5B,UAAM,SAAU,cAAc,SAAS,YAAY,MAAM,KAAK;AAG9D,UAAM,SAAS,cAAc,SAAS,YAAY,MAAM,KAAK;AAC7D,UAAM,WAAW,cAAc,SAAS,YAAY,SAAS;AAC7D,UAAM,mBAAmB;AAAA,MACvB,cAAc,SAAS,YAAY,iBAAiB;AAAA,IACtD;AAEA,UAAM,SAAqB;AAAA,MACzB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,QAAQ,uBAAuB,MAAM;AAAA,MACrC,UAAU,WAAW,uBAAuB,QAAQ,IAAI;AAAA,MACxD;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,sBAAsB,WAAW,aAAa;AAC3D,UAAM,WAAW,cAAc,SAAS,YAAY,QAAQ,KAAK;AACjE,UAAM,gBAAgB,cAAc,SAAS,YAAY,cAAc,KAAK;AAC5E,UAAM,sBAAsB,cAAc,SAAS,YAAY,iBAAiB,KAAK;AAErF,UAAM,OAAiB;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA,UAAU,uBAAuB,QAAQ;AAAA,MACzC,eAAe,uBAAuB,aAAa;AAAA,MACnD,kBAAkB,sBACd,oBAAoB,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,uBAAuB,EAAE,KAAK,CAAC,CAAC,EAAE,OAAO,OAAO,IAC1F,CAAC;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,YAAY;AACzB,UAAM,MAAe;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,qBAAqB,QAOV;AACzB,QAAM,UAAkC;AAAA,IACtC,CAAC,YAAY,OAAO,GAAG;AAAA,IACvB,CAAC,YAAY,MAAM,GAAG;AAAA,IACtB,CAAC,YAAY,OAAO,GAAG,OAAO;AAAA,EAChC;AACA,MAAI,OAAO,eAAe,MAAM;AAC9B,YAAQ,YAAY,OAAO,IAAI,OAAO,OAAO,WAAW;AAAA,EAC1D;AACA,MAAI,OAAO,aAAa,SAAS,GAAG;AAClC,YAAQ,YAAY,aAAa,IAAI,OAAO,aAAa,KAAK,GAAG;AAAA,EACnE;AACA,QAAM,kBAAkB,+BAA+B,OAAO,eAAe;AAC7E,MAAI,iBAAiB;AACnB,YAAQ,YAAY,gBAAgB,IAAI;AAAA,EAC1C;AACA,MAAI,OAAO,cAAc;AACvB,YAAQ,YAAY,cAAc,IAAI,OAAO;AAAA,EAC/C;AACA,SAAO;AACT;AAKO,SAAS,gBAAgB,MAAkD;AAChF,SAAO;AAAA,IACL,CAAC,YAAY,OAAO,GAAG;AAAA,IACvB,CAAC,YAAY,MAAM,GAAG;AAAA,IACtB,CAAC,YAAY,OAAO,GAAG,KAAK;AAAA,EAC9B;AACF;AAKO,SAAS,mBAAmB,QAMR;AACzB,QAAM,UAAkC;AAAA,IACtC,CAAC,YAAY,OAAO,GAAG;AAAA,IACvB,CAAC,YAAY,MAAM,GAAG;AAAA,IACtB,CAAC,YAAY,OAAO,GAAG,OAAO;AAAA,IAC9B,CAAC,YAAY,MAAM,GAAG,OAAO;AAAA,IAC7B,CAAC,YAAY,MAAM,GAAG,OAAO;AAAA,EAC/B;AACA,MAAI,OAAO,UAAU;AACnB,YAAQ,YAAY,SAAS,IAAI,OAAO;AAAA,EAC1C;AACA,QAAM,mBAAmB,uBAAuB,OAAO,gBAAgB;AACvE,MAAI,kBAAkB;AACpB,YAAQ,YAAY,iBAAiB,IAAI;AAAA,EAC3C;AACA,SAAO;AACT;AAKO,SAAS,iBAAiB,QAKN;AACzB,SAAO;AAAA,IACL,CAAC,YAAY,OAAO,GAAG;AAAA,IACvB,CAAC,YAAY,MAAM,GAAG;AAAA,IACtB,CAAC,YAAY,OAAO,GAAG,OAAO;AAAA,IAC9B,CAAC,YAAY,QAAQ,GAAG,OAAO;AAAA,IAC/B,CAAC,YAAY,cAAc,GAAG,OAAO;AAAA,IACrC,CAAC,YAAY,iBAAiB,GAAG,OAAO,iBAAiB,KAAK,GAAG;AAAA,EACnE;AACF;;;ACvUO,IAAM,cAAN,MAAyC;AAAA,EAC7B,YAAY,oBAAI,IAAiC;AAAA,EACjD,eAAe,oBAAI,QAA4B;AAAA,EAEhE,GAA2B,OAAU,UAA0C;AAC7E,UAAM,SAAS,KAAK,UAAU,IAAI,KAAK,KAAK,oBAAI,IAAc;AAC9D,WAAO,IAAI,QAAoB;AAC/B,SAAK,UAAU,IAAI,OAAO,MAAM;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,KAA6B,OAAU,UAA0C;AAC/E,UAAM,UAAoB,IAAI,SAAoB;AAChD,WAAK,IAAI,OAAO,QAAQ;AACvB,MAAC,SAAsB,GAAG,IAAI;AAAA,IACjC;AACA,SAAK,aAAa,IAAI,UAAsB,OAAO;AACnD,WAAO,KAAK,GAAG,OAAO,OAAmC;AAAA,EAC3D;AAAA,EAEA,IAA4B,OAAU,UAA0C;AAC9E,UAAM,SAAS,KAAK,UAAU,IAAI,KAAK;AACvC,QAAI,CAAC;AAAQ,aAAO;AAEpB,UAAM,WAAW;AACjB,UAAM,UAAU,KAAK,aAAa,IAAI,QAAQ;AAC9C,WAAO,OAAO,WAAW,QAAQ;AACjC,QAAI;AAAS,WAAK,aAAa,OAAO,QAAQ;AAC9C,QAAI,OAAO,SAAS;AAAG,WAAK,UAAU,OAAO,KAAK;AAClD,WAAO;AAAA,EACT;AAAA,EAEU,KAA6B,UAAa,MAAqC;AACvF,UAAM,SAAS,KAAK,UAAU,IAAI,KAAK;AACvC,QAAI,CAAC,UAAU,OAAO,SAAS;AAAG,aAAO;AAEzC,eAAW,YAAY,CAAC,GAAG,MAAM,GAAG;AAClC,eAAS,GAAG,IAAI;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AACF;;;AHiBA,SAAS,cAAc,KAAsB;AAC3C,MAAI,EAAE,eAAe;AAAQ,WAAO,OAAO,GAAG;AAE9C,QAAM,QAAQ,CAAC,IAAI,OAAO;AAC1B,QAAM,UAAU;AAShB,MAAI,QAAQ;AAAM,UAAM,KAAK,QAAQ,QAAQ,IAAI,EAAE;AACnD,MAAI,QAAQ,UAAU;AAAW,UAAM,KAAK,SAAS,QAAQ,KAAK,EAAE;AACpE,MAAI,QAAQ;AAAS,UAAM,KAAK,WAAW,QAAQ,OAAO,EAAE;AAC5D,MAAI,QAAQ;AAAS,UAAM,KAAK,WAAW,QAAQ,OAAO,EAAE;AAC5D,MAAI,QAAQ,SAAS;AAAW,UAAM,KAAK,QAAQ,QAAQ,IAAI,EAAE;AAEjE,MAAI,QAAQ,iBAAiB,OAAO;AAClC,UAAM,KAAK,SAAS,cAAc,QAAQ,KAAK,CAAC,EAAE;AAAA,EACpD,WAAW,QAAQ,UAAU,QAAW;AACtC,UAAM,KAAK,SAAS,OAAO,QAAQ,KAAK,CAAC,EAAE;AAAA,EAC7C;AAEA,SAAO,MAAM,KAAK,KAAK;AACzB;AAeO,IAAM,iBAAN,cAA6B,YAA4B;AAAA,EACtD,KAAuB;AAAA,EACvB,UAA8B;AAAA,EAC9B,iBAAwC;AAAA,EACxC,YAAmC;AAAA,EACnC,YAAmC;AAAA,EACnC,kBAAyC;AAAA,EAChC,iBAAiB,oBAAI,IAAY;AAAA,EAC1C,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,aAAa;AAAA;AAAA,EAEb,aAA4B;AAAA,EACnB,cAAc,KAAK,IAAI;AAAA,EAEvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EAExC,YAAY,MAOT;AACD,UAAM;AACN,SAAK,QAAQ,KAAK;AAClB,SAAK,WAAW,KAAK;AACrB,SAAK,UAAU,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAC7C,SAAK,oBAAoB,KAAK,qBAAqB;AACnD,SAAK,qBAAqB,KAAK,sBAAsB;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AACf,SAAK,gBAAgB;AACrB,UAAM,KAAK,QAAQ;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,SAAK,UAAU;AACf,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,WAAW;AAClB,mBAAa,KAAK,SAAS;AAC3B,WAAK,YAAY;AAAA,IACnB;AACA,QAAI,KAAK,WAAW;AAClB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AAAA,IACnB;AACA,QAAI,KAAK,iBAAiB;AACxB,oBAAc,KAAK,eAAe;AAClC,WAAK,kBAAkB;AAAA,IACzB;AACA,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAM;AACd,WAAK,KAAK;AAAA,IACZ;AACA,SAAK,YAAY;AACjB,SAAK,gBAAgB;AACrB,SAAK,aAAa;AAAA,EACpB;AAAA,EAEQ,gBAAwB;AAC9B,UAAM,QAAQ,GAAG,KAAK,KAAK,IAAI,KAAK,QAAQ;AAC5C,WAAO,SAAS,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,CAAC;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAAqC;AACjD,UAAM,MAAM,GAAG,KAAK,OAAO;AAC3B,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,MAAM,KAAK;AAAA,QACrB,SAAS,EAAE,eAAe,KAAK,cAAc,EAAE;AAAA,MACjD,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,IAAI,MAAM,gBAAgB,GAAG,YAAY,cAAc,GAAG,CAAC,EAAE;AAAA,IACrE;AAEA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,MAAM,iCAAiC,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,IACjF;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,SACZ,SAC6B;AAC7B,QAAI,CAAC,KAAK;AAAS,YAAM,IAAI,MAAM,iBAAiB;AAKpD,UAAM,SAAS,GAAG,KAAK,OAAO;AAC9B,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ;AAAA,QACxB,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,eAAe,KAAK,cAAc;AAAA,UAClC,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,OAAO;AAAA,YACL;AAAA,YACA;AAAA,UACF;AAAA,UACA,aAAa;AAAA,QACf,CAAC;AAAA,MACH,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,IAAI,MAAM,YAAY,MAAM,YAAY,cAAc,GAAG,CAAC,EAAE;AAAA,IACpE;AAEA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,EAAE;AAAA,IACvD;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eAAe,WAAkC;AAC7D,UAAM,WAAW,MAAM,KAAK,SAAS;AAAA,MACnC,CAAC,aAAa,EAAE,WAAW,KAAK,CAAC,EAAE,GAAG,IAAI;AAAA,IAC5C,CAAC;AACD,UAAM,UAAU,SAAS,gBAAgB,KAAK,CAAC,CAAC,IAAI,MAAM,SAAS,WAAW;AAC9E,QAAI,SAAS;AACX,WAAK,aAAc,QAAQ,CAAC,EAAyB,SAAS;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,iBAAiB,WAAmB,YAA0C;AAC1F,UAAM,cAAc,MAAM,KAAK,SAAS;AAAA,MACtC,CAAC,iBAAiB,EAAE,WAAW,YAAY,YAAY,GAAG,GAAG,IAAI;AAAA,IACnE,CAAC;AAED,UAAM,gBAAgB,YAAY,gBAAgB,KAAK,CAAC,CAAC,IAAI,MAAM,SAAS,eAAe;AAG3F,QAAI,CAAC,iBAAiB,cAAc,CAAC,MAAM,SAAS;AAClD,YAAM,KAAK,eAAe,SAAS;AACnC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAU,cAAc,CAAC;AAM/B,QAAI,QAAQ,UAAU;AACpB,WAAK,aAAa,QAAQ;AAAA,IAC5B;AAEA,UAAM,SAAS,QAAQ,WAAW,CAAC;AACnC,QAAI,OAAO,WAAW;AAAG,aAAO,CAAC;AAEjC,UAAM,YAAY,MAAM,KAAK,SAAS;AAAA,MACpC;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA,KAAK;AAAA,UACL,YAAY,CAAC,MAAM,WAAW,QAAQ,MAAM,WAAW,aAAa,cAAc,YAAY,cAAc,aAAa;AAAA,UACzH,qBAAqB;AAAA,UACrB,mBAAmB;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,YAAY,UAAU,gBAAgB,KAAK,CAAC,CAAC,IAAI,MAAM,SAAS,WAAW;AACjF,QAAI,CAAC;AAAW,aAAO,CAAC;AAExB,UAAM,OAAO,UAAU,CAAC;AACxB,WAAO,KAAK,QAAQ,CAAC;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,aAAa,OAAwB;AAE3C,UAAM,YAAoC,CAAC;AAC3C,eAAW,KAAK,MAAM,WAAW,CAAC,GAAG;AACnC,gBAAU,EAAE,KAAK,YAAY,CAAC,IAAI,EAAE,MAAM,KAAK;AAAA,IACjD;AAEA,UAAM,WAAW,MAAM,OAAO,CAAC,GAAG,SAAS;AAC3C,UAAM,SAAS,MAAM,KAAK,CAAC,GAAG,SAAS;AACvC,UAAM,YAAY,MAAM,YAAY,CAAC,KAAK,MAAM;AAEhD,QAAI,KAAK,eAAe,IAAI,SAAS;AAAG;AACxC,SAAK,eAAe,IAAI,SAAS;AAGjC,UAAM,MAA0B,iBAAiB;AAAA,MAC/C,MAAM;AAAA,MACN,IAAI;AAAA,MACJ;AAAA,MACA,SAAS,MAAM,WAAW;AAAA,MAC1B,SAAS;AAAA,IACX,CAAC;AAED,QAAI,OAAO,YAAY,KAAK;AAE1B,YAAM,iBAAiB,MAAM,WAAW,CAAC,GAAG;AAC5C,YAAM,eAAe,kBAAkB,MAAM,aAAa,cAAc,GAAG,SAAS,IAAI,KAAK,IAAI;AAChG,MAAC,IAA2C,WAAW;AAGxD,YAAM,uBAAuB,MAAM,eAAe,CAAC,GAAG,IAAI,QAAM;AAAA,QAC9D,UAAU,EAAE,QAAQ;AAAA,QACpB,aAAa,EAAE;AAAA,QACf,MAAM,EAAE;AAAA,QACR,QAAQ,EAAE;AAAA,MACZ,EAAE;AACF,UAAI,oBAAoB,SAAS,GAAG;AAClC;AAAC,QAAC,IAA2C,cAAc;AAAA,MAC7D;AAGA,UAAK,IAA2B,WAAW,iBAAiB;AAC1D,aAAK,KAAK,YAAY,EAAE,IAAI,UAAU,QAAS,IAA2B,QAAQ,UAAU,CAAC;AAAA,MAC/F;AAEA,YAAM,UAAU;AAChB,cAAQ,QAAQ,QAAQ;AAAA,QACtB,KAAK;AACH,eAAK,KAAK,iBAAiB,OAAO;AAClC;AAAA,QACF,KAAK;AACH,eAAK,KAAK,eAAe,OAAO;AAChC;AAAA,QACF,KAAK;AACH,eAAK,KAAK,oBAAoB,OAAO;AACrC,eAAK,KAAK,aAAa,OAAO;AAC9B;AAAA,QACF,KAAK;AACH,eAAK,KAAK,YAAY,OAAO;AAC7B;AAAA,MACJ;AACA;AAAA,IACF;AAKA,UAAM,eAAe,UAAU,aAAa,KAAK;AACjD,QAAI,CAAC;AAAc;AAInB,UAAM,gBAAgB,UAAU,YAAY,KAAK;AACjD,UAAM,gBAAgB,cACnB,MAAM,KAAK,EACX,IAAI,CAAC,MAAM,EAAE,QAAQ,SAAS,EAAE,EAAE,KAAK,CAAC,EACxC,OAAO,OAAO;AAEjB,UAAM,YAAY,aAAa,QAAQ,SAAS,EAAE,EAAE,KAAK;AAGzD,UAAM,aAAa,MAAM,WAAW,CAAC,GAAG;AACxC,UAAM,WAAW,cAAc,MAAM,aAAa,UAAU,GAAG,SAAS,IAAI,KAAK,IAAI;AAErF,UAAM,QAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,SAAS,MAAM,WAAW;AAAA,MAC1B;AAAA,IACF;AAGA,QAAI,cAAc,SAAS,GAAG;AAC5B,aAAO,OAAO,OAAO,EAAE,YAAY,cAAc,CAAC;AAAA,IACpD;AAEA,SAAK,KAAK,SAAS,KAAK;AAAA,EAC1B;AAAA,EAEA,MAAc,kBAAkB,WAAyC;AACvE,UAAM,YAAY,MAAM,KAAK,SAAS;AAAA,MACpC;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA,MAAM,CAAC,EAAE,UAAU,cAAc,aAAa,MAAM,CAAC;AAAA,UACrD,OAAO;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,cAAc,UAAU,gBAAgB,KAAK,CAAC,CAAC,IAAI,MAAM,SAAS,aAAa;AACrF,QAAI,CAAC;AAAa,aAAO,CAAC;AAE1B,UAAM,OAAQ,YAAY,CAAC,EAAyB,OAAO,CAAC,GAAG,MAAM,GAAG,EAAE;AAC1E,QAAI,IAAI,WAAW;AAAG,aAAO,CAAC;AAE9B,UAAM,YAAY,MAAM,KAAK,SAAS;AAAA,MACpC;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA,YAAY,CAAC,MAAM,WAAW,QAAQ,MAAM,WAAW,aAAa,cAAc,YAAY,cAAc,aAAa;AAAA,UACzH,qBAAqB;AAAA,UACrB,mBAAmB;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,YAAY,UAAU,gBAAgB,KAAK,CAAC,CAAC,IAAI,MAAM,SAAS,WAAW;AACjF,QAAI,CAAC;AAAW,aAAO,CAAC;AAExB,WAAQ,UAAU,CAAC,EAA6B,QAAQ,CAAC;AAAA,EAC3D;AAAA,EAEQ,4BAA4B,OAA2B;AAC7D,UAAM,eAAe,IAAI,KAAK,MAAM,UAAU,EAAE,QAAQ;AAGxD,WAAO,OAAO,SAAS,YAAY,KAAK,gBAAgB,KAAK,cAAc;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,UAAyB;AACrC,QAAI,KAAK,cAAc,CAAC,KAAK;AAAS;AACtC,SAAK,aAAa;AAElB,QAAI;AACF,WAAK,UAAU,MAAM,KAAK,aAAa;AAAA,IACzC,SAAS,KAAK;AACZ,WAAK,aAAa;AAClB,WAAK,KAAK,SAAS,IAAI,MAAM,+BAAgC,IAAc,OAAO,EAAE,CAAC;AACrF,WAAK,aAAa,sBAAsB;AACxC,WAAK,kBAAkB;AACvB;AAAA,IACF;AAQA,UAAM,gBAAgB,GAAG,KAAK,OAAO,WAClC,QAAQ,eAAe,QAAQ,EAC/B,QAAQ,cAAc,OAAO;AAEhC,SAAK,KAAK,IAAI,UAAU,eAAe,QAAQ;AAAA,MAC7C,SAAS;AAAA,QACP,eAAe,KAAK,cAAc;AAAA,MACpC;AAAA,MACA,mBAAmB;AAAA,MACnB,oBAAoB,KAAK;AAAA,IAC3B,CAAC;AAED,SAAK,GAAG,GAAG,uBAAuB,CAAC,MAAM,QAAQ;AAC/C,WAAK,aAAa;AAClB,YAAM,gBAAgB,OAAO,QAAQ,IAAI,OAAO,EAC7C,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,KAAK,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAK,SAAS,EAAG,EAAE,EAC1F,KAAK,IAAI;AACZ,WAAK,aAAa,+BAA+B,IAAI,cAAc,SAAS,EAAE;AAC9E,WAAK;AAAA,QACH;AAAA,QACA,IAAI;AAAA,UACF,oCAAoC,IAAI,cAAc,SAAS,IAAI,IAAI,iBAAiB,EAAE,GAAG,gBAAgB,eAAe,aAAa,KAAK,EAAE;AAAA,QAClJ;AAAA,MACF;AACA,WAAK,kBAAkB;AAAA,IACzB,CAAC;AAED,SAAK,GAAG,GAAG,QAAQ,YAAY;AAC7B,WAAK,aAAa;AAClB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,mBAAmB;AAKxB,YAAM,YAAY,KAAK,SAAS,gBAAgB,2BAA2B;AAC3E,UAAI,aAAa,KAAK,eAAe,MAAM;AACzC,cAAM,KAAK,eAAe,SAAS;AAAA,MACrC;AAGA,WAAK,GAAI;AAAA,QACP,KAAK,UAAU;AAAA,UACb,SAAS;AAAA,UACT,WAAW,CAAC,OAAO;AAAA,UACnB,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAEA,WAAK,KAAK,WAAW;AAAA,IACvB,CAAC;AAED,SAAK,GAAG,GAAG,QAAQ,MAAM;AAAA,IAEzB,CAAC;AAED,SAAK,GAAG,GAAG,WAAW,OAAO,YAA+B;AAC1D,UAAI;AACF,cAAM,MAAM,KAAK,MAAM,QAAQ,SAAS,CAAC;AAIzC,YAAI,IAAI,OAAO,MAAM,eAAe;AAClC,gBAAM,KAAK,kBAAkB,GAAG;AAAA,QAClC;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,KAAK,SAAS,IAAI,MAAM,wCAAyC,IAAc,OAAO,EAAE,CAAC;AAAA,MAChG;AAAA,IACF,CAAC;AAED,SAAK,GAAG,GAAG,SAAS,CAAC,MAAM,WAAW;AACpC,WAAK,aAAa;AAClB,WAAK,YAAY;AACjB,WAAK,kBAAkB;AACvB,YAAM,YAAY,QAAQ,SAAS,KAAK;AACxC,WAAK,aAAa,SAAS;AAC3B,WAAK,KAAK,gBAAgB,SAAS;AAEnC,UAAI,KAAK,SAAS;AAChB,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF,CAAC;AAED,SAAK,GAAG,GAAG,SAAS,CAAC,QAAQ;AAC3B,WAAK,aAAa;AAClB,WAAK,kBAAkB;AACvB,WAAK,aAAa,IAAI,OAAO;AAC7B,WAAK,KAAK,SAAS,GAAG;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEQ,qBAA2B;AACjC,QAAI,KAAK,WAAW;AAClB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AAAA,IACnB;AAEA,SAAK,YAAY,YAAY,MAAM;AACjC,UAAI,CAAC,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU;AAAM;AACvD,UAAI;AACF,aAAK,GAAG,KAAK;AAAA,MACf,SAAS,KAAK;AACZ,aAAK,KAAK,SAAS,IAAI,MAAM,kCAAmC,IAAc,OAAO,EAAE,CAAC;AAAA,MAC1F;AAAA,IACF,GAAG,KAAK,cAAc;AAAA,EACxB;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK,WAAW;AAClB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,KAAK;AAAiB;AAE1B,SAAK,kBAAkB,YAAY,MAAM;AACvC,UAAI,CAAC,KAAK;AAAS;AAEnB,WAAK,KAAK,sBAAsB,EAAE,EAAE,MAAM,CAAC,QAAQ;AACjD,aAAK,KAAK,SAAS,IAAI,MAAM,4BAA6B,IAAc,OAAO,EAAE,CAAC;AAAA,MACpF,CAAC;AAAA,IACH,GAAG,KAAK,oBAAoB;AAAA,EAC9B;AAAA,EAEA,MAAc,kBAAkB,aAA6C;AAC3E,QAAI,CAAC,KAAK;AAAS;AAEnB,UAAM,YAAY,KAAK,QAAQ,gBAAgB,2BAA2B;AAC1E,QAAI,CAAC;AAAW;AAEhB,UAAM,iBAAiB,YAAY,QAAQ,SAAS;AACpD,QAAI,CAAC,gBAAgB;AAAO;AAE5B,QAAI;AACF,UAAI,KAAK,eAAe,MAAM;AAG5B,cAAM,KAAK,eAAe,SAAS;AACnC;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,KAAK,iBAAiB,WAAW,KAAK,UAAU;AACrE,iBAAW,SAAS,QAAQ;AAC1B,aAAK,aAAa,KAAK;AAAA,MACzB;AAAA,IACF,SAAS,KAAK;AACZ,WAAK,KAAK,SAAS,IAAI,MAAM,2BAA4B,IAAc,OAAO,EAAE,CAAC;AAAA,IACnF;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK;AAAgB;AAEzB,SAAK,iBAAiB,WAAW,YAAY;AAC3C,WAAK,iBAAiB;AACtB,UAAI,KAAK,SAAS;AAChB,cAAM,KAAK,QAAQ;AAAA,MACrB;AAAA,IACF,GAAG,KAAK,iBAAiB;AAAA,EAC3B;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,aAAa,KAAK;AAAA,EAChC;AAAA,EAEA,yBAAkC;AAChC,WAAO,KAAK,iBAAiB,CAAC,KAAK;AAAA,EACrC;AAAA,EAEQ,cAAoB;AAC1B,QAAI,KAAK,WAAW;AAClB,mBAAa,KAAK,SAAS;AAC3B,WAAK,YAAY;AAAA,IACnB;AACA,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,aAAa,QAAsB;AACzC,QAAI,CAAC,KAAK,WAAW,KAAK;AAAe;AAEzC,SAAK,gBAAgB;AACrB,SAAK,KAAK,SAAS,IAAI,MAAM,wDAAwD,MAAM,EAAE,CAAC;AAC9F,SAAK,KAAK,WAAW;AAErB,UAAM,OAAO,YAAY;AACvB,UAAI,CAAC,KAAK,WAAW,KAAK,WAAW;AACnC,aAAK,YAAY;AACjB;AAAA,MACF;AAEA,UAAI;AACF,YAAI,CAAC,KAAK,SAAS;AACjB,eAAK,UAAU,MAAM,KAAK,aAAa;AAAA,QACzC;AAEA,cAAM,YAAY,KAAK,QAAQ,gBAAgB,2BAA2B,KACrE,OAAO,KAAK,KAAK,QAAQ,QAAQ,EAAE,CAAC;AAEzC,YAAI,CAAC,WAAW;AACd,gBAAM,IAAI,MAAM,2CAA2C;AAAA,QAC7D;AAEA,YAAI,KAAK,eAAe,MAAM;AAC5B,gBAAM,eAAe,MAAM,KAAK,kBAAkB,SAAS;AAC3D,qBAAW,SAAS,aAAa,KAAK,CAAC,GAAG,MAAM;AAC9C,kBAAM,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ;AAC3C,kBAAM,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ;AAC3C,mBAAO,MAAM;AAAA,UACf,CAAC,GAAG;AACF,gBAAI,CAAC,KAAK,4BAA4B,KAAK;AAAG;AAC9C,iBAAK,aAAa,KAAK;AAAA,UACzB;AACA,gBAAM,KAAK,eAAe,SAAS;AAAA,QACrC,OAAO;AACL,gBAAM,SAAS,MAAM,KAAK,iBAAiB,WAAW,KAAK,UAAU;AACrE,qBAAW,SAAS,QAAQ;AAC1B,iBAAK,aAAa,KAAK;AAAA,UACzB;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,KAAK,SAAS,IAAI,MAAM,4BAA6B,IAAc,OAAO,EAAE,CAAC;AAAA,MACpF,UAAE;AACA,YAAI,KAAK,WAAW,CAAC,KAAK,WAAW;AACnC,eAAK,YAAY,WAAW,MAAM,KAAK,iBAAiB;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAEA,SAAK,YAAY,WAAW,MAAM,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,QAAgB,UAAoC;AACrE,QAAI,CAAC,KAAK,SAAS;AAEjB,WAAK,UAAU,MAAM,KAAK,aAAa;AAAA,IACzC;AAEA,UAAM,YAAY,KAAK,QAAQ,gBAAgB,2BAA2B,KACrE,OAAO,KAAK,KAAK,QAAQ,QAAQ,EAAE,CAAC;AAGzC,QAAI,cAAc,KAAK,QAAQ,eAC1B,GAAG,KAAK,OAAO;AAIpB,QAAI;AACF,YAAM,SAAS,IAAI,IAAI,WAAW;AAClC,YAAM,aAAa,IAAI,IAAI,KAAK,OAAO;AACvC,aAAO,WAAW,WAAW;AAC7B,aAAO,OAAO,WAAW;AACzB,oBAAc,OAAO,SAAS;AAAA,IAChC,QAAQ;AAAA,IAER;AAEA,UAAM,eAAe,YAAY;AACjC,kBAAc,YACX,QAAQ,mCAAmC,mBAAmB,SAAS,CAAC,EACxE,QAAQ,6BAA6B,mBAAmB,MAAM,CAAC,EAC/D,QAAQ,yBAAyB,mBAAmB,YAAY,CAAC,EACjE,QAAQ,yBAAyB,0BAA0B;AAI9D,UAAM,cAAc;AACpB,QAAI,aAA4B;AAChC,aAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,YAAM,MAAM,MAAM,MAAM,aAAa;AAAA,QACnC,SAAS,EAAE,eAAe,KAAK,cAAc,EAAE;AAAA,MACjD,CAAC;AACD,mBAAa,IAAI;AACjB,UAAI,IAAI,IAAI;AACV,cAAM,cAAc,MAAM,IAAI,YAAY;AAC1C,eAAO,OAAO,KAAK,WAAW;AAAA,MAChC;AACA,UAAI,UAAU,gBAAgB,IAAI,WAAW,OAAO,IAAI,WAAW,OAAO,IAAI,WAAW,MAAM;AAC7F,gBAAQ;AAAA,UACN,yCAAyC,IAAI,MAAM,YAAY,OAAO,IAAI,WAAW,QAAQ,WAAW;AAAA,QAC1G;AACA,cAAM,QAAQ,KAAK,IAAI,MAAO,KAAK,IAAI,GAAG,UAAU,CAAC,GAAG,IAAK;AAC7D,cAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,KAAK,CAAC;AAC3C;AAAA,MACF;AACA,cAAQ;AAAA,QACN,0CAA0C,IAAI,MAAM,YAAY,OAAO,IAAI,WAAW,QAAQ,WAAW;AAAA,MAC3G;AACA,YAAM,IAAI;AAAA,QACR,gCAAgC,IAAI,MAAM,YAAY,OAAO,IAAI,WAAW,WAAW,MAAM,aAAa,YAAY,YAAY,QAAQ,WAAW;AAAA,MACvJ;AAAA,IACF;AACA,UAAM,IAAI;AAAA,MACR,8CAA8C,cAAc,SAAS,YAAY,WAAW,IAAI,WAAW,WAAW,MAAM,aAAa,YAAY,YAAY,QAAQ,WAAW;AAAA,IACtL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBAAsB,QAAQ,IAAqB;AACvD,QAAI,CAAC,KAAK,SAAS;AACjB,WAAK,UAAU,MAAM,KAAK,aAAa;AAAA,IACzC;AAEA,UAAM,YAAY,KAAK,QAAQ,gBAAgB,2BAA2B,KACrE,OAAO,KAAK,KAAK,QAAQ,QAAQ,EAAE,CAAC;AAEzC,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AAEA,UAAM,YAAY,MAAM,KAAK,SAAS;AAAA,MACpC;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA,MAAM,CAAC,EAAE,UAAU,cAAc,aAAa,MAAM,CAAC;AAAA,UACrD;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,cAAc,UAAU,gBAAgB,KAAK,CAAC,CAAC,IAAI,MAAM,SAAS,aAAa;AACrF,QAAI,CAAC;AAAa,aAAO;AAEzB,UAAM,OAAQ,YAAY,CAAC,EAAyB,OAAO,CAAC,GAAG,MAAM,GAAG,KAAK;AAC7E,QAAI,IAAI,WAAW;AAAG,aAAO;AAE7B,UAAM,YAAY,MAAM,KAAK,SAAS;AAAA,MACpC;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA,YAAY,CAAC,MAAM,WAAW,QAAQ,MAAM,WAAW,aAAa,cAAc,YAAY,cAAc,aAAa;AAAA,UACzH,qBAAqB;AAAA,UACrB,mBAAmB;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,YAAY,UAAU,gBAAgB,KAAK,CAAC,CAAC,IAAI,MAAM,SAAS,WAAW;AACjF,QAAI,CAAC;AAAW,aAAO;AAEvB,UAAM,SAAU,UAAU,CAAC,EAA6B,QAAQ,CAAC;AACjE,eAAW,SAAS,OAAO,KAAK,CAAC,GAAG,MAAM;AACxC,YAAM,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ;AAC3C,YAAM,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ;AAC3C,aAAO,MAAM;AAAA,IACf,CAAC,GAAG;AACF,UAAI,CAAC,KAAK,4BAA4B,KAAK;AAAG;AAC9C,WAAK,aAAa,KAAK;AAAA,IACzB;AAEA,WAAO,OAAO;AAAA,EAChB;AACF;;;AIv1BA,SAAS,uBAAyC;AAClD,SAAS,kBAAkB;AAG3B,IAAM,WAAW,CAAC,MAAc,EAAE,QAAQ,WAAW,GAAG,EAAE,KAAK;AAoBxD,IAAM,aAAN,MAAiB;AAAA,EAGtB,YAA6B,QAAoB;AAApB;AAC3B,SAAK,YAAY,gBAAgB;AAAA,MAC/B,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO,UAAU;AAAA,MACzB,MAAM;AAAA,QACJ,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,MACf;AAAA,MACA,KAAK;AAAA,QACH,oBAAoB,OAAO,sBAAsB;AAAA,MACnD;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAfQ;AAAA,EAiBA,eAAuB;AAC7B,WAAO,KAAK,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY,KAAK;AAAA,EAC1D;AAAA,EAEQ,gBAAgB,OAAuB;AAC7C,WAAO,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY,KAAK;AAAA,EAC/C;AAAA,EAEQ,sBAAsB,IAAqB;AACjD,WAAO;AAAA,MACL,KAAK,OAAO,eACT,KAAK,OAAO,aACZ,KAAK,aAAa,KAClB,KAAK,aAAa,MAAM,KAAK,gBAAgB,EAAE;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,MAAc,YAAY,MAMU;AAClC,UAAM,OAAO,KAAK,OAAO,aAAa,QAAQ,OAAO,EAAE;AACvD,QAAI,CAAC,QAAQ,CAAC,KAAK,OAAO,WAAW;AACnC,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AAEA,UAAM,MAAM,MAAM,MAAM,GAAG,IAAI,aAAa;AAAA,MAC1C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,SAAS,KAAK,OAAO,SAAS;AAAA,QAC7C,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACnB,IAAI,KAAK;AAAA,QACT,SAAS,KAAK;AAAA,QACd,MAAM,KAAK;AAAA,QACX,aAAa,KAAK;AAAA,QAClB,aAAa,KAAK,aAAa,IAAI,CAAC,OAAO;AAAA,UACzC,UAAU,EAAE;AAAA,UACZ,aAAa,EAAE;AAAA,UACf,SAAS,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,EAAE,QAAQ,SAAS,QAAQ;AAAA,QAClF,EAAE;AAAA,MACJ,CAAC;AAAA,IACH,CAAC;AAED,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,MAAM,KAAK,WAAW,qBAAqB,IAAI,MAAM,EAAE;AAAA,IACnE;AACA,WAAO,EAAE,WAAW,KAAK,UAAU;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAS,MAAuE;AACpF,UAAM,SAAS,WAAW;AAC1B,UAAM,cAAc,qBAAqB;AAAA,MACvC;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,cAAc,KAAK,gBAAgB,CAAC;AAAA,MACpC,cAAc,KAAK;AAAA,IACrB,CAAC;AAED,UAAM,eAAwC;AAAA,MAC5C,MAAM,KAAK,OAAO;AAAA,MAClB,IAAI,KAAK;AAAA,MACT,SAAS,eAAe,SAAS,KAAK,KAAK,CAAC;AAAA,MAC5C,MAAM;AAAA,QACJ,SAAS,KAAK,KAAK;AAAA,QACnB,YAAY,MAAM;AAAA,QAClB,KAAK,cAAc,aAAa,KAAK,WAAW,MAAM;AAAA,QACtD,KAAK,cAAc,SACf;AAAA,EAAa,KAAK,aAAa,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,KAC9D;AAAA,QACJ,KAAK,YAAY;AAAA,QACjB;AAAA,QACA;AAAA,MACF,EACG,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,MACZ,SAAS;AAAA,IACX;AAEA,QAAI,KAAK,aAAa,QAAQ;AAC5B,mBAAa,cAAc,KAAK,YAAY,IAAI,QAAM;AAAA,QACpD,UAAU,EAAE;AAAA,QACZ,SAAS,OAAO,EAAE,YAAY,WAAW,OAAO,KAAK,EAAE,SAAS,QAAQ,IAAI,EAAE;AAAA,QAC9E,aAAa,EAAE;AAAA,MACjB,EAAE;AAAA,IACJ;AAEA,QAAI,KAAK,sBAAsB,KAAK,EAAE,GAAG;AACvC,YAAMA,QAAO,MAAM,KAAK,YAAY;AAAA,QAClC,IAAI,KAAK;AAAA,QACT,SAAS,aAAa;AAAA,QACtB,MAAM,aAAa;AAAA,QACnB;AAAA,QACA,aAAa,KAAK,aAAa,IAAI,QAAM;AAAA,UACvC,UAAU,EAAE;AAAA,UACZ,aAAa,EAAE;AAAA,UACf,SAAS,OAAO,EAAE,YAAY,WAAW,OAAO,KAAK,EAAE,SAAS,QAAQ,IAAI,EAAE;AAAA,QAChF,EAAE;AAAA,MACJ,CAAC;AACD,aAAO,EAAE,QAAQ,WAAWA,MAAK,aAAa,GAAG;AAAA,IACnD;AAEA,UAAM,OAAO,MAAM,KAAK,UAAU,SAAS,YAAY;AAEvD,WAAO,EAAE,QAAQ,WAAW,KAAK,aAAa,GAAG;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,MAAwC;AACvD,UAAM,cAAc,mBAAmB;AAAA,MACrC,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,kBAAkB,KAAK;AAAA,IACzB,CAAC;AAED,UAAM,WAAoC;AAAA,MACxC,MAAM,KAAK,OAAO;AAAA,MAClB,IAAI,KAAK;AAAA,MACT,SAAS,sBAAsB,KAAK,MAAM,WAAM,KAAK,MAAM;AAAA,MAC3D,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,YAAY,KAAK,MAAM;AAAA,QACvB,WAAW,KAAK,MAAM;AAAA,QACtB;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,KAAK,WAAW;AAAA,SAAY,KAAK,QAAQ,KAAK;AAAA,MAChD,EACG,OAAO,CAAC,MAAM,MAAM,EAAE,EACtB,KAAK,IAAI;AAAA,MACZ,SAAS;AAAA,IACX;AACA,QAAI,KAAK,WAAW;AAClB,eAAS,YAAY,KAAK;AAC1B,eAAS,aAAa,KAAK;AAAA,IAC7B;AACA,QAAI,KAAK,aAAa,QAAQ;AAC5B,eAAS,cAAc,KAAK,YAAY,IAAI,QAAM;AAAA,QAChD,UAAU,EAAE;AAAA,QACZ,SAAS,OAAO,EAAE,YAAY,WAAW,OAAO,KAAK,EAAE,SAAS,QAAQ,IAAI,EAAE;AAAA,QAC9E,aAAa,EAAE;AAAA,MACjB,EAAE;AAAA,IACJ;AAEA,QAAI,KAAK,sBAAsB,KAAK,EAAE,GAAG;AACvC,YAAM,KAAK,YAAY;AAAA,QACrB,IAAI,KAAK;AAAA,QACT,SAAS,SAAS;AAAA,QAClB,MAAM,SAAS;AAAA,QACf;AAAA,QACA,aAAa,KAAK,aAAa,IAAI,QAAM;AAAA,UACvC,UAAU,EAAE;AAAA,UACZ,aAAa,EAAE;AAAA,UACf,SAAS,OAAO,EAAE,YAAY,WAAW,OAAO,KAAK,EAAE,SAAS,QAAQ,IAAI,EAAE;AAAA,QAChF,EAAE;AAAA,MACJ,CAAC;AACD;AAAA,IACF;AACA,UAAM,KAAK,UAAU,SAAS,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,MAAsC;AACnD,UAAM,cAAc,iBAAiB;AAAA,MACnC,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,eAAe,KAAK;AAAA,MACpB,kBAAkB,KAAK;AAAA,IACzB,CAAC;AAED,UAAM,eAAwC;AAAA,MAC5C,MAAM,KAAK,OAAO;AAAA,MAClB,IAAI,KAAK;AAAA,MACT,SAAS,oBAAoB,KAAK,MAAM;AAAA,MACxC,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,YAAY,KAAK,MAAM;AAAA,QACvB;AAAA,QACA,aAAa,KAAK,QAAQ;AAAA,QAC1B;AAAA,QACA,mBAAmB,KAAK,aAAa;AAAA,QACrC;AAAA,QACA,KAAK,iBAAiB,SAClB;AAAA,EAAuB,KAAK,iBAAiB,IAAI,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,KACzF;AAAA,MACN,EACG,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,MACZ,SAAS;AAAA,IACX;AACA,QAAI,KAAK,WAAW;AAClB,mBAAa,YAAY,KAAK;AAC9B,mBAAa,aAAa,KAAK;AAAA,IACjC;AACA,QAAI,KAAK,aAAa,QAAQ;AAC5B,mBAAa,cAAc,KAAK,YAAY,IAAI,QAAM;AAAA,QACpD,UAAU,EAAE;AAAA,QACZ,SAAS,OAAO,EAAE,YAAY,WAAW,OAAO,KAAK,EAAE,SAAS,QAAQ,IAAI,EAAE;AAAA,QAC9E,aAAa,EAAE;AAAA,MACjB,EAAE;AAAA,IACJ;AAEA,QAAI,KAAK,sBAAsB,KAAK,EAAE,GAAG;AACvC,YAAM,KAAK,YAAY;AAAA,QACrB,IAAI,KAAK;AAAA,QACT,SAAS,aAAa;AAAA,QACtB,MAAM,aAAa;AAAA,QACnB;AAAA,QACA,aAAa,KAAK,aAAa,IAAI,QAAM;AAAA,UACvC,UAAU,EAAE;AAAA,UACZ,aAAa,EAAE;AAAA,UACf,SAAS,OAAO,EAAE,YAAY,WAAW,OAAO,KAAK,EAAE,SAAS,QAAQ,IAAI,EAAE;AAAA,QAChF,EAAE;AAAA,MACJ,CAAC;AACD;AAAA,IACF;AACA,UAAM,KAAK,UAAU,SAAS,YAAY;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,MAAyE;AACrF,UAAM,cAAc,gBAAgB,EAAE,QAAQ,KAAK,OAAO,CAAC;AAC3D,UAAM,WAAoC;AAAA,MACxC,MAAM,KAAK,OAAO;AAAA,MAClB,IAAI,KAAK;AAAA,MACT,SAAS,mBAAmB,KAAK,MAAM;AAAA,MACvC,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AACA,QAAI,KAAK,WAAW;AAClB,eAAS,YAAY,KAAK;AAC1B,eAAS,aAAa,KAAK;AAAA,IAC7B;AAEA,QAAI,KAAK,sBAAsB,KAAK,EAAE,GAAG;AACvC,YAAM,KAAK,YAAY;AAAA,QACrB,IAAI,KAAK;AAAA,QACT,SAAS,SAAS;AAAA,QAClB,MAAM,SAAS;AAAA,QACf;AAAA,MACF,CAAC;AACD;AAAA,IACF;AACA,UAAM,KAAK,UAAU,SAAS,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAA2B;AAC/B,QAAI;AACF,YAAM,KAAK,UAAU,OAAO;AAC5B,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;;;ACzRO,IAAM,aAAN,cAAyB,YAA8B;AAAA,EACpD;AAAA,EACA;AAAA,EACS;AAAA,EAEjB,YAAY,QAA0B;AACpC,UAAM;AACN,SAAK,SAAS;AAGd,QAAI;AACJ,QAAI;AACF,YAAM,UAAU,OAAO,KAAK,OAAO,WAAW,QAAQ,EAAE,SAAS,OAAO;AACxE,YAAM,WAAW,QAAQ,QAAQ,GAAG;AACpC,UAAI,WAAW;AAAG,cAAM,IAAI,MAAM,2DAA2D;AAC7F,iBAAW,QAAQ,MAAM,WAAW,CAAC;AACrC,UAAI,CAAC;AAAU,cAAM,IAAI,MAAM,mCAAmC;AAAA,IACpE,SAAS,KAAK;AACZ,UAAI,eAAe,SAAS,IAAI,QAAQ,WAAW,mBAAmB;AAAG,cAAM;AAC/E,YAAM,IAAI,MAAM,+BAAgC,IAAc,OAAO,EAAE;AAAA,IACzE;AAEA,SAAK,aAAa,IAAI,eAAe;AAAA,MACnC,OAAO,OAAO;AAAA,MACd,UAAU,YAAY,OAAO;AAAA,MAC7B,SAAS,OAAO;AAAA,MAChB,mBAAmB,OAAO,qBAAqB;AAAA,MAC/C,oBAAoB,OAAO;AAAA,IAC7B,CAAC;AAED,SAAK,aAAa,IAAI,WAAW;AAAA,MAC/B,MAAM,OAAO;AAAA,MACb,MAAM,OAAO,YAAY;AAAA,MACzB,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,MACjB,aAAa,OAAO,mBAAmB,OAAO;AAAA,MAC9C,WAAW,OAAO;AAAA,MAClB,oBAAoB,OAAO;AAAA,IAC7B,CAAC;AAGD,SAAK,WAAW,GAAG,iBAAiB,CAAC,SAAuB;AAC1D,WAAK,KAAK,iBAAiB,IAAI;AAAA,IACjC,CAAC;AAED,SAAK,WAAW,GAAG,eAAe,CAAC,WAAuB;AACxD,WAAK,KAAK,eAAe,MAAM;AAAA,IACjC,CAAC;AAED,SAAK,WAAW,GAAG,oBAAoB,CAAC,SAAmB;AACzD,WAAK,KAAK,oBAAoB,IAAI;AAClC,WAAK,KAAK,aAAa,IAAI;AAAA,IAC7B,CAAC;AAED,SAAK,WAAW,GAAG,YAAY,CAAC,QAAiB;AAC/C,WAAK,KAAK,YAAY,GAAG;AAAA,IAC3B,CAAC;AAGD,SAAK,WAAW,GAAG,YAAY,OAAO,EAAE,IAAI,QAAQ,UAAU,MAAyD;AACrH,UAAI;AACF,cAAM,KAAK,WAAW,QAAQ,EAAE,IAAI,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpE,SAAS,KAAK;AACZ,gBAAQ,KAAK,sCAAsC,MAAM,KAAM,IAAc,OAAO,EAAE;AAAA,MACxF;AAAA,IACF,CAAC;AAED,SAAK,WAAW,GAAG,SAAS,CAAC,UAAsB;AACjD,WAAK,KAAK,SAAS,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,WAAW,GAAG,aAAa,MAAM;AACpC,WAAK,KAAK,WAAW;AAAA,IACvB,CAAC;AAED,SAAK,WAAW,GAAG,gBAAgB,CAAC,WAAmB;AACrD,WAAK,KAAK,gBAAgB,MAAM;AAAA,IAClC,CAAC;AAED,SAAK,WAAW,GAAG,SAAS,CAAC,QAAe;AAC1C,WAAK,KAAK,SAAS,GAAG;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,UAAyB;AAC7B,UAAM,KAAK,WAAW,MAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,WAAW,KAAK;AACrB,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,WAAW,YAAY;AAAA,EACrC;AAAA,EAEA,yBAAkC;AAChC,WAAO,KAAK,WAAW,uBAAuB;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,SAAS,MAAuE;AACpF,WAAO,KAAK,WAAW,SAAS,IAAI;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,MAAwC;AACvD,WAAO,KAAK,WAAW,WAAW,IAAI;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,MAAsC;AACnD,WAAO,KAAK,WAAW,SAAS,IAAI;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAa,QAAgB,UAAoC;AACrE,WAAO,KAAK,WAAW,aAAa,QAAQ,QAAQ;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBAAsB,OAAiC;AAC3D,WAAO,KAAK,WAAW,sBAAsB,KAAK;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA+B;AACnC,WAAO,KAAK,WAAW,OAAO;AAAA,EAChC;AAAA,EAEA,IAAI,QAAgB;AAClB,WAAO,KAAK,OAAO;AAAA,EACrB;AACF;;;AC1NA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,SAAS,YAAY;AAC9B,SAAS,eAAe;AAQjB,SAAS,yBAAiC;AAC/C,SAAO,KAAK,QAAQ,GAAG,aAAa,cAAc,wBAAwB,mBAAmB;AAC/F;AAEO,SAAS,mBAAmB,MAAgC;AACjE,QAAM,WAAW,QAAQ,uBAAuB;AAChD,MAAI,CAAC,WAAW,QAAQ;AAAG,WAAO;AAClC,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,aAAa,UAAU,OAAO,CAAC;AACzD,QAAI,CAAC,OAAO,SAAS,CAAC,OAAO,aAAa,CAAC,OAAO;AAAc,aAAO;AACvE,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,UAAoB,MAAqB;AAC1E,QAAM,WAAW,QAAQ,uBAAuB;AAChD,YAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,gBAAc,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AACpE;AAEO,SAAS,UAAU,KAAmB;AAC3C,YAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC;AAEO,SAAS,eAAe,MAAsB;AACnD,SAAO,aAAa,IAAI;AAC1B;AAEO,SAAS,gBAAgB,MAAc,SAAoC;AAChF,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,gBAAc,MAAM,OAAO;AAC7B;;;ACqCA,SAAS,kBACP,MACA,gBACuC;AACvC,MAAI,CAAC,gBAAgB;AAAQ,WAAO,EAAE,SAAS,KAAK;AAEpD,QAAM,SAAS,KAAK,KAAK,YAAY;AACrC,QAAM,SAAS,eAAe,KAAK,CAAC,SAAS,KAAK,OAAO,KAAK,EAAE,YAAY,MAAM,MAAM;AACxF,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,SAAS,OAAO,QAAQ,UAAU,KAAK,IAAI,oCAAoC;AAAA,EAC1F;AAEA,QAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,SAAS,OAAO,KAAK,KAAK,EAAE,WAAW,GAAG;AAC7C,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AAEA,QAAM,UAAU,KAAK,mBAAmB,CAAC;AACzC,QAAM,iBAAiB,OAAO,QAAQ,KAAK,EACxC,IAAI,CAAC,CAAC,KAAK,aAAa,MAAM;AAAA,IAC7B;AAAA,KACC,iBAAiB,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,EACnE,CAAU,EACT,OAAO,CAAC,CAAC,EAAE,aAAa,MAAM,cAAc,SAAS,CAAC;AAEzD,MAAI,eAAe,WAAW,GAAG;AAC/B,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AAEA,aAAW,CAAC,KAAK,aAAa,KAAK,gBAAgB;AACjD,UAAM,eAAe,QAAQ,GAAG;AAChC,QAAI,CAAC,cAAc;AACjB,aAAO,EAAE,SAAS,OAAO,QAAQ,yCAAyC,GAAG,IAAI;AAAA,IACnF;AACA,QAAI,CAAC,cAAc,SAAS,YAAY,GAAG;AACzC,aAAO,EAAE,SAAS,OAAO,QAAQ,mBAAmB,GAAG,IAAI,YAAY,kBAAkB;AAAA,IAC3F;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,KAAK;AACzB;AAYA,SAAS,QAAQ,UAA0B;AACzC,MAAI,SAAS,WAAW,SAAS,KAAK,SAAS,WAAW,UAAU,GAAG;AACrE,WAAO,SAAS,QAAQ,OAAO,EAAE;AAAA,EACnC;AACA,SAAO,WAAW,QAAQ;AAC5B;AAEA,IAAM,eAAe,oBAAI,IAAyB;AAElD,IAAM,qBAAqB,oBAAI,IAAwF;AAOvH,IAAM,oBAAoB,oBAAI,IAAyE;AACvG,IAAI,aAAgC;AACpC,IAAI,aAAa;AACjB,IAAI,sBAAsB;AAC1B,IAAI,uBAAuB;AAC3B,IAAI,oBAA8D;AAClE,IAAI,0BAAoE;AACxE,IAAI,iBAAwC;AAC5C,IAAI,wBAA+C;AAGnD,IAAI,oBAAoB;AAGxB,IAAI,iBAAsB;AAE1B,IAAI,aAAkB;AAEtB,SAAS,kBACP,KACA,MACA,OACA,cACM;AACN,MAAI,SAAS;AAAc;AAE3B,MAAI,SAAS,WAAW;AACtB,QAAI,OAAO,KAAK,kEAA6D,KAAK,EAAE;AACpF;AAAA,EACF;AAEA,MAAI,iBAAiB,WAAW;AAC9B,QAAI,OAAO,KAAK,iDAA4C,KAAK,EAAE;AACnE;AAAA,EACF;AAEA,MAAI,OAAO,KAAK,wCAAmC,KAAK,EAAE;AAC5D;AAiBA,eAAe,aAAa,KAAsC;AAChE,QAAM,QAAQ,IAAI,QAAQ,kBACvB,YAAY,EACZ,QAAQ,WAAW,GAAG,EACtB,QAAQ,eAAe,EAAE;AAE5B,QAAM,OAAO,QAAQ,IAAI,QAAQ;AAGjC,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,4BAA4B;AAAA,IACzD,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,aAAa,2BAA2B,CAAC;AAAA,EACxE,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,MAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,UAAM,IAAI,MAAM,6BAA6B,IAAI,MAAM,MAAM,IAAI,SAAS,IAAI,UAAU,EAAE;AAAA,EAC5F;AAEA,QAAM,UAAW,MAAM,IAAI,KAAK;AAMhC,QAAM,UAAU,MAAM;AAAA,IACpB,GAAG,IAAI,+BAA+B,mBAAmB,QAAQ,gBAAgB,CAAC;AAAA,EACpF;AAEA,MAAI,CAAC,QAAQ,IAAI;AACf,UAAM,MAAO,MAAM,QAAQ,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAClD,UAAM,IAAI,MAAM,oCAAoC,QAAQ,MAAM,MAAM,IAAI,SAAS,QAAQ,UAAU,EAAE;AAAA,EAC3G;AAEA,QAAM,WAAY,MAAM,QAAQ,KAAK;AAMrC,SAAO;AAAA,IACL,OAAO,SAAS;AAAA,IAChB,WAAW,SAAS,KAAK;AAAA,IACzB,cAAc,SAAS,KAAK;AAAA,EAC9B;AACF;AAOA,eAAe,gBAAgB,KAAsC;AACnE,QAAM,SAAS,mBAAmB,IAAI,mBAAmB,uBAAuB,CAAC;AACjF,MAAI;AAAQ,WAAO;AAEnB,QAAM,WAAW,MAAM,aAAa,GAAG;AACvC,qBAAmB,UAAU,IAAI,mBAAmB,uBAAuB,CAAC;AAC5E,SAAO;AACT;AAIA,IAAO,cAAQ;AAAA,EACb,IAAI;AAAA,EACJ,MAAM;AAAA,EAEN,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,YAAY;AAAA,MACV,UAAU;AAAA,QACR,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,MACA,iBAAiB;AAAA,QACf,MAAM;AAAA,QACN,aACE;AAAA,MAGJ;AAAA,MACA,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,aACE;AAAA,QAEF,OAAO;AAAA,UACL,MAAM;AAAA,UACN,UAAU,CAAC,QAAQ;AAAA,UACnB,YAAY;AAAA,YACV,QAAQ;AAAA,cACN,MAAM;AAAA,cACN,aAAa;AAAA,YACf;AAAA,YACA,sBAAsB;AAAA,cACpB,MAAM;AAAA,cACN,aACE;AAAA,cAEF,sBAAsB;AAAA,gBACpB,MAAM;AAAA,gBACN,OAAO,EAAE,MAAM,SAAS;AAAA,cAC1B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,SAAS,KAAU;AAGjB,UAAM,MAAQ,IAAI,QAAQ,UAAU,QAAQ,IAAI,gBAAgB,CAAC;AAOjE,QAAI,gBAAgB;AAAA,MAClB,IAAI;AAAA,MACJ,MAAM,EAAE,OAAO,OAAO;AAAA,MACtB,cAAc,EAAE,WAAW,CAAC,IAAI,EAAE;AAAA,MAClC,QAAQ;AAAA,QACN,gBAAgB,MAAM,IAAI,WAAW,CAAC,SAAS,IAAI,CAAC;AAAA,QACpD,gBAAgB,OAAO,EAAE,UAAU,IAAI,SAAS;AAAA,QAChD,WAAW,MAAM,CAAC,CAAC,IAAI;AAAA,QACvB,cAAc,MAAM,CAAC,CAAC,mBAAmB,IAAI,mBAAmB,uBAAuB,CAAC;AAAA,MAC1F;AAAA,MACA,SAAS;AAAA,QACP,cAAc,OAAO,QAAgF;AAEnG,2BAAiB,IAAI,kBAAkB;AACvC,uBAAa,IAAI,OAAO;AACxB,cAAI,OAAO,KAAK,wDAAmD,iBAAiB,cAAc,eAAe,EAAE;AAGnH,gBAAM,IAAI,QAAc,CAAC,YAAY;AACnC,gBAAI,aAAa,iBAAiB,SAAS,MAAM,QAAQ,CAAC;AAAA,UAC5D,CAAC;AACD,2BAAiB;AACjB,uBAAa;AAAA,QACf;AAAA,QACA,aAAa,YAAY;AACvB,2BAAiB;AACjB,uBAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF,CAAC;AAED,aAAS,qBAAqB,YAAoB,OAAqB;AACrE,UAAI;AACF,YAAI,QAAQ,OAAO,oBAAoB,EAAE,QAAQ,QAAQ,WAAW,CAAC;AACrE,YAAI,OAAO,KAAK,kCAAkC,KAAK,gBAAgB,UAAU,EAAE;AAAA,MACrF,SAAS,KAAK;AACZ,YAAI,OAAO,KAAK,0CAA0C,KAAK,KAAM,IAAc,OAAO,EAAE;AAAA,MAC9F;AAAA,IACF;AAEA,aAAS,wBAAwB,MAAyB;AACxD,YAAM,WAAW,MAAM,qBAAqB,mBAAmB,QAAQ,KAAK,MAAM,EAAE;AACpF,YAAM,aAAa,gBAAgB,OAAO;AAE1C,UAAI,OAAO;AAAA,QACT,kCAAkC,KAAK,MAAM,0BAAqB,iBAAiB,QAAQ,IAAI,eAAe,aAAa,QAAQ,IAAI,eAAe,OAAO,eAAe,aAAa,QAAQ,IAAI,YAAY,iBAAiB;AAAA,MACpO;AAEA,UAAI,CAAC,kBAAkB,CAAC,cAAc,OAAO,eAAe,YAAY;AACtE,iBAAS;AACT;AAAA,MACF;AAEA,YAAM,SAAS;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAEX,UAAI;AACF,aAAK,QAAQ,QAAQ,WAAW;AAAA,UAC9B,KAAK;AAAA,YACH,MAAM,KAAK,YAAY,KAAK;AAAA,YAC5B,cAAc;AAAA,YACd,MAAM,KAAK;AAAA,YACX,IAAI;AAAA,YACJ,YAAY,qBAAqB,KAAK,MAAM;AAAA,YAC5C,WAAW;AAAA,YACX,UAAU;AAAA,YACV,UAAU;AAAA,YACV,SAAS;AAAA,YACT,oBAAoB;AAAA,YACpB,eAAe,KAAK;AAAA,YACpB,YAAY,KAAK,aAAa,KAAK;AAAA,YACnC,WAAW,KAAK,IAAI;AAAA,YACpB,YAAY,KAAK;AAAA,YACjB,UAAU,KAAK;AAAA,YACf,mBAAmB;AAAA,UACrB;AAAA,UACA,KAAK;AAAA,UACL,mBAAmB;AAAA,YACjB,SAAS,YAAY;AAAA,YAAC;AAAA,YACtB,SAAS,CAAC,QAAiB;AACzB,kBAAI,OAAO,MAAM,0CAA0C,KAAK,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,YAC/H;AAAA,UACF;AAAA,QACF,CAAC,CAAC,EAAE,KAAK,MAAM;AACb,cAAI,OAAO,KAAK,8CAA8C,KAAK,MAAM,EAAE;AAAA,QAC7E,CAAC,EAAE,MAAM,CAAC,QAAe;AACvB,cAAI,OAAO,MAAM,2CAA2C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;AACzF,mBAAS;AAAA,QACX,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,YAAI,OAAO,MAAM,wDAAwD,KAAK,MAAM,KAAM,IAAc,OAAO,EAAE;AACjH,iBAAS;AAAA,MACX;AAAA,IACF;AAGA,mBAAe,UAAU,UAAsE;AAC7F,UAAI,gBAAgB;AAClB,sBAAc,cAAc;AAC5B,yBAAiB;AAAA,MACnB;AACA,UAAI,uBAAuB;AACzB,sBAAc,qBAAqB;AACnC,gCAAwB;AAAA,MAC1B;AAEA,mBAAa,SAAS;AACtB,4BAAsB;AACtB,6BAAuB;AACvB,0BAAoB;AACpB,gCAA0B;AAC1B,UAAI,OAAO,KAAK,wCAAmC,UAAU,EAAE;AAI/D,YAAM,OAAO,QAAQ,IAAI,QAAQ;AAEjC,mBAAa,IAAI,WAAW;AAAA,QAC1B,OAAO,SAAS;AAAA,QAChB,WAAW,SAAS;AAAA,QACpB,SAAS;AAAA,QACT,UAAU,IAAI,IAAI,IAAI,EAAE;AAAA,QACxB,UAAU;AAAA,QACV,cAAc,SAAS;AAAA;AAAA;AAAA,QAGvB,oBAAoB;AAAA,MACtB,CAAC;AAED,iBAAW,GAAG,iBAAiB,CAAC,SAAuB;AACrD,YAAI,OAAO,KAAK,gCAA2B,KAAK,MAAM,MAAM,KAAK,KAAK,WAAW,KAAK,IAAI,EAAE;AAE5F,YAAI;AAEF,gBAAM,WAAW,kBAAkB,MAAM,IAAI,cAAc;AAC3D,cAAI,CAAC,SAAS,SAAS;AACrB,gBAAI,OAAO,KAAK,6CAAwC,KAAK,IAAI,UAAU,KAAK,MAAM,YAAY,SAAS,MAAM,EAAE;AACnH,iBAAK,WAAY,WAAW;AAAA,cAC1B,IAAI,KAAK;AAAA,cACT,QAAQ,KAAK;AAAA,cACb,QAAQ;AAAA,cACR,QAAQ;AAAA,cACR,UAAU,SAAS,UAAU,UAAU,KAAK,IAAI;AAAA,YAClD,CAAC,EAAE,MAAM,CAAC,QAAe;AACvB,kBAAI,OAAO,MAAM,4CAA4C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;AAAA,YAC5F,CAAC;AACD;AAAA,UACF;AAEA,uBAAa,IAAI,KAAK,QAAQ;AAAA,YAC5B,QAAQ,KAAK;AAAA,YACb,MAAM,KAAK;AAAA,YACX,OAAO,KAAK;AAAA,YACZ,UAAU,KAAK,YAAY;AAAA,YAC3B,cAAc,KAAK;AAAA,YACnB,aAAa,KAAK;AAAA,YAClB,WAAW,KAAK,aAAa;AAAA,YAC7B,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,UACrC,CAAC;AAKD,kCAAwB,aAAa,IAAI,KAAK,MAAM,CAAE;AAAA,QACxD,SAAS,KAAK;AACZ,cAAI,OAAO,MAAM,2CAA2C,KAAK,MAAM,KAAM,IAAc,OAAO,EAAE;AACpG,cAAI,aAAa,IAAI,KAAK,MAAM,GAAG;AACjC,iCAAqB,mBAAmB,QAAQ,KAAK,MAAM,EAAE;AAAA,UAC/D;AAAA,QACF;AAAA,MACF,CAAC;AAGD,iBAAW,GAAG,eAAe,CAAC,WAAuB;AACnD,YAAI,OAAO,KAAK,8BAAyB,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,OAAO,IAAI,EAAE;AAEtG,cAAM,MAAM,mBAAmB,IAAI,OAAO,MAAM;AAChD,2BAAmB,OAAO,OAAO,MAAM;AAGvC,cAAM,SAAS,kBAAkB,IAAI,OAAO,MAAM;AAClD,YAAI,QAAQ;AACV,4BAAkB,OAAO,OAAO,MAAM;AACtC,cAAI,OAAO,KAAK,6CAA6C,OAAO,MAAM,EAAE;AAC5E,iBAAO,EAAE,MAAM,UAAU,MAAM,OAAO,CAAC;AACvC;AAAA,QACF;AAIA,cAAM,kBAA2E,CAAC;AAClF,cAAM,mBAAmB,YAAY;AACnC,cAAI,CAAC,OAAO,aAAa;AAAQ;AACjC,gBAAM,MAAM;AACZ,oBAAU,GAAG;AACb,qBAAW,OAAO,OAAO,aAAa;AACpC,gBAAI;AACF,oBAAM,SAAS,MAAM,WAAY,aAAa,IAAI,QAAQ,IAAI,QAAQ;AACtE,oBAAM,WAAW,GAAG,GAAG,IAAI,IAAI,QAAQ;AACvC,8BAAgB,UAAU,MAAM;AAChC,8BAAgB,KAAK,EAAE,UAAU,IAAI,UAAU,MAAM,UAAU,MAAM,OAAO,OAAO,CAAC;AACpF,kBAAI,OAAO,KAAK,0BAA0B,IAAI,QAAQ,MAAM,OAAO,SAAS,MAAM,QAAQ,CAAC,CAAC,eAAU,QAAQ,EAAE;AAAA,YAClH,SAAS,OAAO;AACd,kBAAI,OAAO,KAAK,kCAAkC,IAAI,QAAQ,KAAM,MAAgB,OAAO,EAAE;AAAA,YAC/F;AAAA,UACF;AAAA,QACF,GAAG;AAEH,wBAAgB,KAAK,MAAM;AAEzB,gBAAM,mBAAmB;AACzB,gBAAM,QAAQ,OAAO,WAAW,cAAc,uBAAuB;AACrE,gBAAM,YAAY,OAAO,UAAU;AACnC,gBAAM,kBAAkB,UAAU,SAAS,mBACvC,UAAU,MAAM,GAAG,gBAAgB,IAAI;AAAA;AAAA,kBAAuB,UAAU,MAAM,kBAC9E;AAEJ,cAAI,iBAAiB;AACrB,cAAI,gBAAgB,SAAS,GAAG;AAC9B,6BAAiB;AAAA;AAAA;AAAA,EAAoD,gBAAgB;AAAA,cAAI,OACvF,KAAK,EAAE,QAAQ,MAAM,EAAE,OAAO,MAAM,QAAQ,CAAC,CAAC,eAAU,EAAE,IAAI;AAAA,YAChE,EAAE,KAAK,IAAI,CAAC;AAAA,0CAA6C,gBAAgB,IAAI,OAAK,gBAAgB,EAAE,QAAQ,aAAa,EAAE,IAAI,KAAK,EAAE,KAAK,IAAI,CAAC;AAAA,UAClJ,WAAW,OAAO,aAAa,QAAQ;AACrC,kBAAM,QAAQ,OAAO,YAAY;AAAA,cAAI,CAAC,MACpC,GAAG,EAAE,QAAQ,MAAM,EAAE,OAAO,MAAM,QAAQ,CAAC,CAAC,gBAAgB,EAAE,MAAM;AAAA,YACtE;AACA,6BAAiB;AAAA;AAAA;AAAA,EAA+E,MAAM,KAAK,IAAI,CAAC;AAAA,UAClH;AAEA,uBAAa,IAAI,UAAU,OAAO,MAAM,IAAI;AAAA,YAC1C,QAAQ,OAAO;AAAA,YACf,MAAM,OAAO;AAAA,YACb,OAAO,GAAG,KAAK,KAAK,KAAK,SAAS,OAAO,MAAM;AAAA,YAC/C,UAAU,OAAO,WAAW,cACxB,SAAS,OAAO,IAAI;AAAA;AAAA;AAAA,EAAwC,eAAe,GAAG,cAAc,KAC5F,SAAS,OAAO,IAAI;AAAA;AAAA,UAAsC,OAAO,YAAY,SAAS;AAAA,YAC1F,cAAc,CAAC;AAAA,YACf,aAAa;AAAA,YACb,WAAW;AAAA,YACX,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,UACrC,CAAC;AAGD,cAAI,kBAAkB,YAAY;AAChC,kBAAM,aAAa,aAAa,IAAI,UAAU,OAAO,MAAM,EAAE;AAC7D,kBAAM,kBAAkB,CAAC,GAAG,aAAa,QAAQ,CAAC,EAC/C,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,WAAW,SAAS,KAAK,CAAC,IAAI,WAAW,OAAO,CAAC,EACxE,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AACnB,kBAAM,gBAAgB,gBAAgB,SAAS,IAC3C;AAAA;AAAA;AAAA;AAAA,EAA6F,gBAAgB,IAAI,OAAK,cAAc,EAAE,MAAM,YAAY,EAAE,IAAI,cAAc,EAAE,KAAK,GAAG,EAAE,KAAK,IAAI,CAAC,KAClM;AACJ,kBAAM,SAAS;AAAA;AAAA,EAAyB,YAAY,YAAY,qBAAqB,GAAG,aAAa;AAErG,2BAAe,MAAM,yCAAyC;AAAA,cAC5D,KAAK;AAAA,gBACH,MAAM,oBAAoB,OAAO,MAAM;AAAA,gBACvC,cAAc;AAAA,gBACd,MAAM,OAAO;AAAA,gBACb,IAAI;AAAA,gBACJ,YAAY,gBAAgB,OAAO,IAAI;AAAA,gBACvC,WAAW;AAAA,gBACX,UAAU;AAAA,gBACV,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,oBAAoB;AAAA,gBACpB,eAAe,OAAO;AAAA,gBACtB,YAAY,OAAO;AAAA,gBACnB,WAAW,KAAK,IAAI;AAAA,gBACpB,YAAY,OAAO;AAAA,gBACnB,UAAU,OAAO;AAAA,gBACjB,mBAAmB;AAAA,cACrB;AAAA,cACA,KAAK;AAAA,cACL,mBAAmB;AAAA,gBACjB,SAAS,YAAY;AAAA,gBAAC;AAAA,gBACtB,SAAS,CAAC,QAAiB;AACzB,sBAAI,OAAO,MAAM,kCAAkC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,gBACvG;AAAA,cACF;AAAA,YACF,CAAC,EAAE,KAAK,MAAM;AACZ,kBAAI,OAAO,KAAK,yDAAyD,OAAO,MAAM,EAAE;AACxF,2BAAa,OAAO,UAAU,OAAO,MAAM,EAAE;AAAA,YAC/C,CAAC,EAAE,MAAM,CAAC,QAAe;AACvB,kBAAI,OAAO,MAAM,mCAAmC,IAAI,OAAO,EAAE;AAAA,YACnE,CAAC;AAAA,UACH,OAAO;AACL,kBAAM,mBAAmB,0BAA0B,KAAK,IAAI,CAAC;AAC7D,gBAAI;AACF,kBAAI,QAAQ,OAAO,oBAAoB,EAAE,QAAQ,QAAQ,YAAY,iBAAiB,CAAC;AACvF,kBAAI,OAAO,KAAK,wCAAwC,OAAO,MAAM,EAAE;AAAA,YACzE,SAAS,KAAK;AACZ,kBAAI,OAAO,KAAK,gDAAiD,IAAc,OAAO,EAAE;AAAA,YAC1F;AAAA,UACF;AAAA,QACF,CAAC,EAAE,MAAM,CAAC,QAAe;AACvB,cAAI,OAAO,MAAM,6CAA6C,IAAI,OAAO,EAAE;AAAA,QAC7E,CAAC;AAAA,MACH,CAAC;AAGD,iBAAW,GAAG,oBAAoB,CAAC,SAAmB;AACpD,YAAI,OAAO,KAAK,mCAA8B,KAAK,MAAM,eAAe,KAAK,QAAQ,WAAW,KAAK,IAAI,EAAE;AAG3G,cAAM,SAAS,kBAAkB,IAAI,KAAK,MAAM;AAChD,YAAI,QAAQ;AACV,4BAAkB,OAAO,KAAK,MAAM;AACpC,cAAI,OAAO,KAAK,kDAAkD,KAAK,MAAM,EAAE;AAC/E,iBAAO,EAAE,MAAM,QAAQ,MAAM,KAAK,CAAC;AACnC;AAAA,QACF;AAEA,cAAM,MAAM,mBAAmB,IAAI,KAAK,MAAM;AAE9C,qBAAa,IAAI,QAAQ,KAAK,MAAM,IAAI;AAAA,UACtC,QAAQ,KAAK;AAAA,UACb,MAAM,KAAK;AAAA,UACX,OAAO,wBAAwB,KAAK,SAAS,KAAK,MAAM;AAAA,UACxD,UAAU,SAAS,KAAK,IAAI;AAAA;AAAA,YAAqD,KAAK,QAAQ;AAAA,kBAAqB,KAAK,aAAa,GAAG,KAAK,kBAAkB,SAAS;AAAA,qBAAwB,KAAK,iBAAiB,KAAK,IAAI,CAAC,KAAK,EAAE;AAAA,UACvO,cAAc,CAAC;AAAA,UACf,aAAa;AAAA,UACb,WAAW;AAAA,UACX,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACrC,CAAC;AAED,YAAI,kBAAkB,YAAY;AAChC,gBAAM,aAAa,aAAa,IAAI,QAAQ,KAAK,MAAM,EAAE;AACzD,gBAAM,SAAS;AAAA;AAAA,EAA+B,YAAY,YAAY,KAAK,QAAQ;AAEnF,yBAAe,MAAM,yCAAyC;AAAA,YAC5D,KAAK;AAAA,cACH,MAAM,kBAAkB,KAAK,MAAM;AAAA,cACnC,cAAc;AAAA,cACd,MAAM,KAAK;AAAA,cACX,IAAI;AAAA,cACJ,YAAY,gBAAgB,KAAK,IAAI;AAAA,cACrC,WAAW;AAAA,cACX,UAAU;AAAA,cACV,UAAU;AAAA,cACV,SAAS;AAAA,cACT,oBAAoB;AAAA,cACpB,eAAe,KAAK;AAAA,cACpB,YAAY,KAAK;AAAA,cACjB,WAAW,KAAK,IAAI;AAAA,cACpB,YAAY,KAAK;AAAA,cACjB,UAAU,KAAK;AAAA,cACf,mBAAmB;AAAA,YACrB;AAAA,YACA,KAAK;AAAA,YACL,mBAAmB;AAAA,cACjB,SAAS,YAAY;AAAA,cAAC;AAAA,cACtB,SAAS,CAAC,QAAiB;AACzB,oBAAI,OAAO,MAAM,yCAAyC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,cAC9G;AAAA,YACF;AAAA,UACF,CAAC,EAAE,KAAK,MAAM;AACZ,yBAAa,OAAO,QAAQ,KAAK,MAAM,EAAE;AAAA,UAC3C,CAAC,EAAE,MAAM,CAAC,QAAe;AACvB,gBAAI,OAAO,MAAM,4CAA4C,IAAI,OAAO,EAAE;AAAA,UAC5E,CAAC;AAAA,QACH,OAAO;AACL,gBAAM,iBAAiB,0BAA0B,KAAK,IAAI,CAAC;AAC3D,cAAI;AACF,gBAAI,QAAQ,OAAO,oBAAoB,EAAE,QAAQ,QAAQ,YAAY,eAAe,CAAC;AACrF,gBAAI,OAAO,KAAK,+CAA+C,KAAK,MAAM,EAAE;AAAA,UAC9E,SAAS,KAAK;AACZ,gBAAI,OAAO,KAAK,8CAA+C,IAAc,OAAO,EAAE;AAAA,UACxF;AAAA,QACF;AAAA,MACF,CAAC;AAED,iBAAW,GAAG,aAAa,MAAM;AAC/B,8BAAsB;AACtB,+BAAuB;AACvB,cAAM,OAAO,YAAY,uBAAuB,IAAI,YAAY;AAChE,0BAAkB,KAAK,MAAM,YAAY,uBAAuB;AAChE,4BAAoB;AACpB,kCAA0B;AAAA,MAC5B,CAAC;AAED,iBAAW,GAAG,gBAAgB,CAAC,WAAmB;AAChD,+BAAuB;AACvB,YAAI,sBAAsB,gBAAgB;AACxC,cAAI,OAAO,KAAK,wBAAwB,MAAM,wBAAwB;AACtE,8BAAoB;AACpB,oCAA0B;AAAA,QAC5B;AAAA,MACF,CAAC;AAED,iBAAW,GAAG,SAAS,CAAC,QAAe;AACrC,8BAAsB,IAAI;AAC1B,YAAI,IAAI,QAAQ,WAAW,sDAAsD,GAAG;AAClF,cAAI,sBAAsB,WAAW;AACnC,8BAAkB,KAAK,WAAW,YAAY,uBAAuB;AACrE,gCAAoB;AACpB,sCAA0B;AAAA,UAC5B;AACA;AAAA,QACF;AACA,YAAI,OAAO,MAAM,UAAU,IAAI,OAAO,EAAE;AAAA,MAC1C,CAAC;AAED,YAAM,WAAW,QAAQ;AAEzB,UAAI,OAAO;AAAA,QACT,yCAAoC,WAAW,uBAAuB,IAAI,qBAAqB,WAAW,OAAO,UAAU;AAAA,MAC7H;AAEA,UAAI,WAAW,YAAY,KAAK,sBAAsB,gBAAgB;AACpE,YAAI,WAAW,uBAAuB,GAAG;AACvC,4BAAkB,KAAK,WAAW,YAAY,uBAAuB;AACrE,8BAAoB;AACpB,oCAA0B;AAAA,QAC5B,OAAO;AACL,4BAAkB,KAAK,aAAa,YAAY,uBAAuB;AACvE,8BAAoB;AACpB,oCAA0B;AAAA,QAC5B;AAAA,MACF;AAEA,iBAAW,MAAM;AACf,YAAI,CAAC,YAAY,YAAY;AAAG;AAChC,cAAM,OAAO,WAAW,uBAAuB,IAAI,YAAY;AAC/D,0BAAkB,KAAK,MAAM,YAAY,uBAAuB;AAChE,4BAAoB;AACpB,kCAA0B;AAAA,MAC5B,GAAG,GAAI;AAEP,8BAAwB,YAAY,MAAM;AACxC,YAAI,CAAC;AAAY;AACjB,YAAI,CAAC,WAAW,YAAY,GAAG;AAC7B,cAAI,sBAAsB,gBAAgB;AACxC,gCAAoB;AAAA,UACtB;AACA;AAAA,QACF;AACA,cAAM,OAAO,WAAW,uBAAuB,IAAI,YAAY;AAC/D,0BAAkB,KAAK,MAAM,YAAY,uBAAuB;AAChE,4BAAoB;AACpB,kCAA0B;AAAA,MAC5B,GAAG,GAAI;AAEP,uBAAiB,YAAY,MAAM;AACjC,YAAI,CAAC;AAAY;AACjB,aAAK,WAAW,sBAAsB,EAAE,EAAE,MAAM,CAAC,QAAe;AAC9D,gCAAsB,IAAI;AAC1B,cAAI,OAAO,KAAK,oCAAoC,IAAI,OAAO,EAAE;AAAA,QACnE,CAAC;AAAA,MACH,GAAG,IAAK;AAAA,IACV;AAKA,QAAI,gBAAgB;AAAA,MAClB,IAAI;AAAA,MACJ,OAAO,YAAY;AACjB,YAAI,CAAC,IAAI,UAAU;AACjB,cAAI,OAAO,KAAK,6DAAwD;AACxE;AAAA,QACF;AACA,YAAI;AACF,gBAAM,WAAW,MAAM,gBAAgB,GAAG;AAC1C,gBAAM,UAAU,QAAQ;AAAA,QAC1B,SAAS,KAAK;AACZ,cAAI,OAAO,KAAK,uCAAwC,IAAc,OAAO,EAAE;AAAA,QACjF;AAAA,MACF;AAAA,MACA,MAAM,MAAM;AACV,YAAI,gBAAgB;AAClB,wBAAc,cAAc;AAC5B,2BAAiB;AAAA,QACnB;AACA,YAAI,uBAAuB;AACzB,wBAAc,qBAAqB;AACnC,kCAAwB;AAAA,QAC1B;AACA,YAAI,YAAY;AACd,cAAI;AACF,uBAAW,WAAW;AACtB,gBAAI,OAAO,KAAK,qCAAqC;AAAA,UACvD,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAOD,QAAI,GAAG,iBAAiB,MAAM;AAC5B,UAAI,aAAa,SAAS;AAAG;AAC7B,UAAI,OAAO,KAAK,qDAAqD,aAAa,IAAI,kBAAkB;AACxG,UAAI;AACF,YAAI,QAAQ,OAAO,oBAAoB,EAAE,QAAQ,QAAQ,YAAY,kBAAkB,CAAC;AAAA,MAC1F,SAAS,KAAK;AACZ,YAAI,OAAO,KAAK,0CAA2C,IAAc,OAAO,EAAE;AAAA,MACpF;AAAA,IACF,CAAC;AAGD,QAAI;AAAA,MACF;AAAA,MACA,CAAC,QAAQ,QAAQ;AAGf,YAAI,KAAK,cAAc,CAAC,OAAO,IAAI,UAAU,EAAE,WAAW,OAAO,GAAG;AAClE,8BAAoB,IAAI;AAAA,QAC1B;AAGA,cAAM,MAAM,KAAK,IAAI;AACrB,mBAAW,CAAC,IAAI,CAAC,KAAK,cAAc;AAClC,cAAI,EAAE,eAAe,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAE,cAAc,KAAM;AAClF,gBAAI,OAAO,KAAK,eAAe,EAAE,uCAAkC;AACnE,yBAAa,OAAO,EAAE;AAAA,UACxB;AAAA,QACF;AAEA,YAAI,aAAa,SAAS;AAAG,iBAAO,CAAC;AAKrC,cAAM,aAAa,CAAC,GAAG,aAAa,QAAQ,CAAC;AAC7C,cAAM,gBAAgB,WAAW,OAAO,CAAC,CAAC,GAAG,MAAM,IAAI,WAAW,SAAS,KAAK,IAAI,WAAW,OAAO,CAAC;AACvG,cAAM,aAAa,WAAW,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,WAAW,SAAS,KAAK,CAAC,IAAI,WAAW,OAAO,CAAC;AAGtG,cAAM,CAAC,SAAS,IAAI,IAAI,cAAc,SAAS,IAC3C,cAAc,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,IACzG,WAAW,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;AAE1G,cAAM,iBAAiB,QAAQ,WAAW,SAAS,KAAK,QAAQ,WAAW,OAAO;AAGlF,YAAI,kBAAkB,SAAS;AAC7B,uBAAa,OAAO,OAAO;AAAA,QAC7B;AAGA,cAAM,kBAAkB,CAAC,GAAG,aAAa,QAAQ,CAAC,EAC/C,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,WAAW,SAAS,KAAK,CAAC,IAAI,WAAW,OAAO,CAAC,EACxE,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AAEnB,cAAM,oBAAoB,mBAAmB,KAAK,UAAU,SAAS,0BAA0B,KAAK;AACpG,cAAM,wBAAwB,kBAAkB,gBAAgB,SAAS,IACrE;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB,gBAAgB,MAAM;AAAA,UACxC;AAAA,UACA;AAAA,UACA,GAAG,gBAAgB;AAAA,YAAI,CAAC,MACtB,cAAc,EAAE,MAAM,YAAY,EAAE,IAAI,cAAc,EAAE,KAAK;AAAA,UAC/D;AAAA,UACA,GAAI,oBAAoB;AAAA,YACtB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF,IAAI,CAAC;AAAA,QACP,EAAE,KAAK,IAAI,IACX;AAEJ,cAAM,QAAQ,iBAAiB;AAAA,UAC7B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa,KAAK,MAAM;AAAA,UACxB,aAAa,KAAK,IAAI;AAAA,UACtB,aAAa,KAAK,KAAK;AAAA,UACvB,KAAK,WAAW;AAAA,EAAK,KAAK,QAAQ,KAAK;AAAA,UACvC;AAAA,UACA,aAAa,OAAO,IAAI;AAAA,IAAO,aAAa,OAAO,CAAC,wBAAwB;AAAA,QAC9E,IAAI;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB,KAAK,MAAM;AAAA,UAC7B;AAAA,UACA,aAAa,KAAK,MAAM;AAAA,UACxB,aAAa,KAAK,IAAI;AAAA,UACtB,aAAa,KAAK,KAAK;AAAA,UACvB,KAAK,WAAW;AAAA,EAAiB,KAAK,QAAQ,KAAK;AAAA,UACnD,KAAK,aAAa,SACd;AAAA,EAAmB,KAAK,aAAa,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,KACtE;AAAA,UACJ,KAAK,cAAc,aAAa,KAAK,WAAW,oBAAoB;AAAA,UACpE,aAAa,KAAK,UAAU;AAAA,UAC5B,aAAa,OAAO,IAAI;AAAA,IAAO,aAAa,OAAO,CAAC,wBAAwB;AAAA,QAC9E,EACG,OAAO,OAAO,EACd,KAAK,IAAI;AAEZ,eAAO,EAAE,gBAAgB,MAAM;AAAA,MACjC;AAAA,MACA,EAAE,UAAU,EAAE;AAAA,IAChB;AAGA,QAAI,aAAa;AAAA,MACf,MAAM;AAAA,MACN,aACE;AAAA,MAEF,YAAY;AAAA,QACV,MAAM;AAAA,QACN,UAAU,CAAC,UAAU,UAAU,QAAQ;AAAA,QACvC,YAAY;AAAA,UACV,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,MAAM,CAAC,aAAa,UAAU;AAAA,YAC9B,aAAa;AAAA,UACf;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,UAAU;AAAA,YACR,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,aAAa;AAAA,YACX,MAAM;AAAA,YACN,aAAa;AAAA,YACb,OAAO;AAAA,cACL,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,UAAU,EAAE,MAAM,SAAS;AAAA,gBAC3B,aAAa,EAAE,MAAM,SAAS;AAAA,gBAC9B,MAAM,EAAE,MAAM,UAAU,aAAa,oCAAoC;AAAA,cAC3E;AAAA,cACA,UAAU,CAAC,YAAY,MAAM;AAAA,YAC/B;AAAA,UACF;AAAA,UACA,kBAAkB;AAAA,YAChB,MAAM;AAAA,YACN,aAAa;AAAA,YACb,OAAO;AAAA,cACL,MAAM;AAAA,cACN,UAAU,CAAC,YAAY,cAAc;AAAA,cACrC,YAAY;AAAA,gBACV,UAAU,EAAE,MAAM,SAAS;AAAA,gBAC3B,cAAc,EAAE,MAAM,SAAS;AAAA,gBAC/B,YAAY,EAAE,MAAM,SAAS;AAAA,gBAC7B,OAAO;AAAA,kBACL,aAAa;AAAA,gBACf;AAAA,gBACA,OAAO,EAAE,MAAM,SAAS;AAAA,gBACxB,qBAAqB;AAAA,kBACnB,MAAM;AAAA,kBACN,OAAO,EAAE,MAAM,SAAS;AAAA,kBACxB,aAAa;AAAA,gBACf;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,OAAO,KAAK,WAAW;AAC9B,cAAM,IAAI;AASV,cAAM,OAAO,aAAa,IAAI,EAAE,MAAM;AACtC,YAAI,CAAC,MAAM;AACT,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAAA,UACzF;AAAA,QACF;AAEA,YAAI,CAAC,YAAY,YAAY,GAAG;AAC9B,iBAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uCAAuC,CAAC,EAAE;AAAA,QACrF;AAEA,YAAI,OAAO,KAAK,kCAAkC,KAAK,UAAU;AAAA,UAC/D,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,UAAU,EAAE;AAAA,UACZ,aAAa,EAAE,aAAa,IAAI,CAAC,OAAO;AAAA,YACtC,UAAU,EAAE;AAAA,YACZ,aAAa,EAAE,eAAe;AAAA,YAC9B,MAAM,EAAE;AAAA,UACV,EAAE,KAAK,CAAC;AAAA,UACR,kBAAkB,EAAE,kBAAkB,IAAI,CAAC,WAAW;AAAA,YACpD,UAAU,MAAM;AAAA,YAChB,cAAc,MAAM;AAAA,YACpB,YAAY,MAAM;AAAA,YAClB,OAAO,MAAM;AAAA,YACb,OAAO,MAAM;AAAA,YACb,qBAAqB,MAAM,uBAAuB,CAAC;AAAA,UACrD,EAAE,KAAK,CAAC;AAAA,QACV,CAAC,CAAC,EAAE;AAGJ,YAAI;AACJ,YAAI,EAAE,aAAa,QAAQ;AACzB,wBAAc,EAAE,YAAY,IAAI,CAAC,OAAiE;AAAA,YAChG,UAAU,EAAE;AAAA,YACZ,aAAa,EAAE,eAAe;AAAA,YAC9B,SAAS,eAAe,EAAE,IAAI;AAAA,UAChC,EAAE;AAAA,QACJ;AAEA,cAAM,WAAW,WAAW;AAAA,UAC1B,IAAI,KAAK;AAAA,UACT,QAAQ,KAAK;AAAA,UACb,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,UAAU,EAAE;AAAA,UACZ,kBAAkB,EAAE,kBAAkB,SAAS,EAAE,mBAAmB;AAAA,UACpE,WAAW,KAAK,aAAa;AAAA,UAC7B;AAAA,QACF,CAAC;AAED,qBAAa,OAAO,KAAK,MAAM;AAC/B,YAAI,OAAO,KAAK,8BAAyB,KAAK,MAAM,KAAK,EAAE,MAAM,EAAE;AAGnE,YAAI,aAAa,OAAO,GAAG;AACzB,cAAI;AACF,gBAAI,QAAQ,OAAO,oBAAoB,EAAE,QAAQ,QAAQ,YAAY,kBAAkB,CAAC;AAAA,UAC1F,QAAQ;AAAA,UAAe;AAAA,QACzB;AAEA,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM,wBAAwB,KAAK,MAAM,aAAa,EAAE,MAAM;AAAA,YAChE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAG/B,QAAI,aAAa;AAAA,MACf,MAAM;AAAA,MACN,aACE;AAAA,MAEF,YAAY;AAAA,QACV,MAAM;AAAA,QACN,UAAU,CAAC,UAAU,YAAY,eAAe;AAAA,QAChD,YAAY;AAAA,UACV,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,UAAU;AAAA,YACR,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,eAAe;AAAA,YACb,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,kBAAkB;AAAA,YAChB,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,OAAO,KAAK,WAAW;AAC9B,cAAM,IAAI;AAOV,cAAM,OAAO,aAAa,IAAI,EAAE,MAAM;AACtC,YAAI,CAAC,MAAM;AACT,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAAA,UACzF;AAAA,QACF;AAEA,YAAI,CAAC,YAAY,YAAY,GAAG;AAC9B,iBAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uCAAuC,CAAC,EAAE;AAAA,QACrF;AAEA,cAAM,WAAW,SAAS;AAAA,UACxB,IAAI,KAAK;AAAA,UACT,QAAQ,KAAK;AAAA,UACb,UAAU,EAAE;AAAA,UACZ,eAAe,EAAE;AAAA,UACjB,kBAAkB,EAAE,oBAAoB,CAAC;AAAA,UACzC,WAAW,KAAK,aAAa;AAAA,QAC/B,CAAC;AAED,YAAI,OAAO,KAAK,mCAA8B,KAAK,MAAM,EAAE;AAG3D,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM,8BAA8B,KAAK,MAAM;AAAA,YACjD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAG7B,QAAI,aAAa;AAAA,MACf,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY,EAAE,MAAM,UAAU,YAAY,CAAC,EAAE;AAAA,MAC7C,SAAS,YAAY;AACnB,YAAI,aAAa,SAAS,GAAG;AAC3B,iBAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,yBAAyB,CAAC,EAAE;AAAA,QACvE;AAEA,cAAM,QAAQ,CAAC,GAAG,aAAa,OAAO,CAAC,EACpC,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,EAClF;AAAA,UACC,CAAC,GAAG,MACF,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,IAAI,EAAE,WAAW;AAAA,kBAAqB,EAAE,QAAQ,KAAK,EAAE,gBAAW,EAAE,IAAI,cAAc,EAAE,UAAU;AAAA,QACzI;AAEF,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM,GAAG,aAAa,IAAI;AAAA,EAAsB,MAAM,KAAK,IAAI,CAAC;AAAA,YAClE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAMjC,QAAI,aAAa;AAAA,MACf,MAAM;AAAA,MACN,aACE;AAAA,MAGF,YAAY;AAAA,QACV,MAAM;AAAA,QACN,UAAU,CAAC,MAAM,OAAO;AAAA,QACxB,YAAY;AAAA,UACV,IAAI,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,UACrE,OAAO,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,UACrE,UAAU,EAAE,MAAM,UAAU,aAAa,4BAA4B;AAAA,UACrE,cAAc,EAAE,MAAM,UAAU,aAAa,gIAAgI;AAAA,UAC7K,aAAa,EAAE,MAAM,UAAU,aAAa,gCAAgC;AAAA,UAC5E,cAAc;AAAA,YACZ,MAAM;AAAA,YAAS,OAAO,EAAE,MAAM,SAAS;AAAA,YACvC,aAAa;AAAA,UACf;AAAA,UACA,aAAa;AAAA,YACX,MAAM;AAAA,YACN,aAAa;AAAA,YACb,OAAO;AAAA,cACL,MAAM;AAAA,cACN,YAAY;AAAA,gBACV,UAAU,EAAE,MAAM,SAAS;AAAA,gBAC3B,aAAa,EAAE,MAAM,SAAS;AAAA,gBAC9B,MAAM,EAAE,MAAM,UAAU,aAAa,oCAAoC;AAAA,cAC3E;AAAA,cACA,UAAU,CAAC,YAAY,MAAM;AAAA,YAC/B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,OAAO,KAAc,WAIxB;AACJ,YAAI,CAAC,YAAY,YAAY,GAAG;AAC9B,iBAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uCAAuC,CAAC,EAAE;AAAA,QACrF;AAEA,YAAI;AAEF,cAAI;AACJ,cAAI,OAAO,aAAa,QAAQ;AAC9B,0BAAc,OAAO,YAAY,IAAI,CAAC,OAAiE;AAAA,cACrG,UAAU,EAAE;AAAA,cACZ,aAAa,EAAE,eAAe;AAAA,cAC9B,SAAS,eAAe,EAAE,IAAI;AAAA,YAChC,EAAE;AAAA,UACJ;AAEA,gBAAM,SAAS,MAAM,WAAW,SAAS;AAAA,YACvC,IAAI,OAAO;AAAA,YACX,OAAO,OAAO;AAAA,YACd,cAAc,OAAO;AAAA,YACrB,aAAa,OAAO;AAAA,YACpB,cAAc,OAAO;AAAA,YACrB;AAAA,UACF,CAAC;AAGD,6BAAmB,IAAI,OAAO,QAAQ;AAAA,YACpC,IAAI,OAAO;AAAA,YACX,OAAO,OAAO;AAAA,YACd,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,YACrC,cAAc,OAAO;AAAA,UACvB,CAAC;AAED,cAAI,OAAO,KAAK,gCAA2B,OAAO,MAAM,QAAQ,OAAO,EAAE,YAAY,OAAO,gBAAgB,MAAM,6BAAwB;AAG1I,gBAAM,aAAa,OAAO,eAAe,OAAO;AAChD,gBAAM,QAAQ,MAAM,IAAI,QAAoD,CAAC,SAAS,WAAW;AAC/F,8BAAkB,IAAI,OAAO,QAAQ,OAAO;AAC5C,uBAAW,MAAM;AACf,kBAAI,kBAAkB,OAAO,OAAO,MAAM,GAAG;AAC3C,uBAAO,IAAI,MAAM,YAAY,OAAO,MAAM,oBAAoB,OAAO,eAAe,GAAG,GAAG,CAAC;AAAA,cAC7F;AAAA,YACF,GAAG,SAAS;AAAA,UACd,CAAC;AAED,cAAI,OAAO,KAAK,gCAA2B,OAAO,MAAM,UAAU,MAAM,IAAI,gBAAgB,KAAK,UAAW,MAAM,MAAc,aAAa,UAAU,CAAC,CAAC,EAAE;AAE3J,cAAI,MAAM,SAAS,UAAU;AAC3B,kBAAM,IAAI,MAAM;AAIhB,gBAAI,kBAAkB;AACtB,gBAAI,EAAE,aAAa,QAAQ;AACzB,kBAAI,OAAO,KAAK,sBAAsB,EAAE,YAAY,MAAM,mCAAmC;AAC7F,oBAAM,MAAM;AACZ,wBAAU,GAAG;AACb,oBAAM,aAAuB,CAAC;AAC9B,oBAAM,OAAO,QAAQ,IAAI,QAAQ;AACjC,oBAAM,WAAW,mBAAmB,IAAI,mBAAmB,uBAAuB,CAAC;AACnF,oBAAM,aAAa,WAAW,SAAS,OAAO,KAAK,SAAS,QAAQ,MAAM,SAAS,YAAY,EAAE,SAAS,QAAQ,CAAC,KAAK;AACxH,yBAAW,OAAO,EAAE,aAAa;AAC/B,oBAAI;AAEF,wBAAM,QAAQ,GAAG,IAAI,oBAAoB,mBAAmB,IAAI,MAAM,CAAC,IAAI,mBAAmB,IAAI,QAAQ,CAAC;AAC3G,sBAAI,OAAO,KAAK,mBAAmB,KAAK,EAAE;AAC1C,wBAAM,QAAQ,MAAM,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,WAAW,EAAE,CAAC;AAC3E,sBAAI,CAAC,MAAM;AAAI,0BAAM,IAAI,MAAM,QAAQ,MAAM,MAAM,EAAE;AACrD,wBAAM,SAAS,OAAO,KAAK,MAAM,MAAM,YAAY,CAAC;AACpD,wBAAM,WAAW,GAAG,GAAG,IAAI,IAAI,QAAQ;AACvC,kCAAgB,UAAU,MAAM;AAChC,6BAAW,KAAK,GAAG,IAAI,QAAQ,MAAM,OAAO,SAAS,MAAM,QAAQ,CAAC,CAAC,eAAU,QAAQ,EAAE;AACzF,sBAAI,OAAO,KAAK,sBAAsB,IAAI,QAAQ,MAAM,OAAO,SAAS,MAAM,QAAQ,CAAC,CAAC,MAAM;AAAA,gBAChG,SAAS,OAAO;AACd,sBAAI,OAAO,MAAM,8BAA8B,IAAI,QAAQ,KAAM,MAAgB,OAAO,EAAE;AAAA,gBAC5F;AAAA,cACF;AACA,kBAAI,WAAW,QAAQ;AACrB,kCAAkB;AAAA;AAAA;AAAA,EAAgC,WAAW,KAAK,IAAI,CAAC;AAAA,cACzE;AAAA,YACF;AAEA,mBAAO;AAAA,cACL,SAAS,CAAC;AAAA,gBACR,MAAM;AAAA,gBACN,MAAM;AAAA,kBACJ,YAAY,EAAE,MAAM,KAAK,OAAO,KAAK;AAAA,kBACrC,UAAU,EAAE,IAAI;AAAA,kBAChB,YAAY,OAAO,MAAM;AAAA,kBACzB,EAAE,WAAW,cAAc;AAAA;AAAA,EAAc,EAAE,MAAM,KAAK;AAAA,SAAY,EAAE,YAAY,UAAU;AAAA,kBAC1F;AAAA,gBACF,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,cAC7B,CAAC;AAAA,YACH;AAAA,UACF,OAAO;AACL,kBAAM,IAAI,MAAM;AAChB,mBAAO;AAAA,cACL,SAAS,CAAC;AAAA,gBACR,MAAM;AAAA,gBACN,MAAM;AAAA,kBACJ,wBAAwB,OAAO,KAAK;AAAA,kBACpC,UAAU,EAAE,IAAI;AAAA,kBAChB,YAAY,OAAO,MAAM;AAAA,kBACzB;AAAA,YAAe,EAAE,QAAQ;AAAA,kBACzB,mBAAmB,EAAE,aAAa;AAAA,kBAClC,EAAE,kBAAkB,SAAS,YAAY,EAAE,iBAAiB,KAAK,KAAK,CAAC,KAAK;AAAA,gBAC9E,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,cAC7B,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,2BAA4B,IAAc,OAAO,GAAG,CAAC;AAAA,UACvF;AAAA,QACF;AAAA,MACF;AAAA,IACF,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAGjC,QAAI,aAAa;AAAA,MACf,MAAM;AAAA,MACN,aACE;AAAA,MAEF,YAAY;AAAA,QACV,MAAM;AAAA,QACN,UAAU,CAAC,OAAO;AAAA,QAClB,YAAY;AAAA,UACV,OAAO,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,QACjE;AAAA,MACF;AAAA,MACA,SAAS,OAAO,KAAc,WAA8B;AAC1D,cAAM,OAAO,QAAQ,IAAI,QAAQ;AACjC,cAAM,QAAQ,QAAQ,SAAS;AAC/B,YAAI,CAAC,OAAO;AACV,iBAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,qCAAqC,CAAC,EAAE;AAAA,QACnF;AACA,YAAI;AACF,gBAAM,eAAe,MAAM,MAAM,GAAG,IAAI,mBAAmB;AAC3D,cAAI,CAAC,aAAa;AAAI,kBAAM,IAAI,MAAM,QAAQ,aAAa,MAAM,EAAE;AACnE,gBAAM,YAAY,MAAM,aAAa,KAAK;AAC1C,gBAAM,SAAS,UAAU,KAAK;AAC9B,cAAI,CAAC;AAAQ,kBAAM,IAAI,MAAM,uCAAuC;AACpE,gBAAM,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,MAAM,oCAAoC,mBAAmB,KAAK,CAAC,EAAE;AACvG,cAAI,CAAC,IAAI;AAAI,kBAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,EAAE;AACjD,gBAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,iBAAO;AAAA,YACL,SAAS,CAAC;AAAA,cACR,MAAM;AAAA,cACN,MAAM,KAAK,OACP,GAAG,OAAO,KAAK,oCAAoC,KAAK,UAAU,SAAS,MAC3E,GAAG,OAAO,KAAK;AAAA,YACrB,CAAC;AAAA,UACH;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,mBAAmB,OAAO,KAAK,KAAM,IAAc,OAAO,GAAG,CAAC;AAAA,UAChG;AAAA,QACF;AAAA,MACF;AAAA,IACF,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAGlC,QAAI,aAAa;AAAA,MACf,MAAM;AAAA,MACN,aACE;AAAA,MAEF,YAAY;AAAA,QACV,MAAM;AAAA,QACN,UAAU,CAAC,UAAU,UAAU;AAAA,QAC/B,YAAY;AAAA,UACV,QAAQ,EAAE,MAAM,UAAU,aAAa,+CAA+C;AAAA,UACtF,UAAU,EAAE,MAAM,UAAU,aAAa,sBAAsB;AAAA,UAC/D,QAAQ,EAAE,MAAM,UAAU,aAAa,kDAAkD;AAAA,QAC3F;AAAA,MACF;AAAA,MACA,SAAS,OAAO,KAAc,WAAkE;AAC9F,YAAI,CAAC,YAAY,YAAY,GAAG;AAC9B,iBAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uCAAuC,CAAC,EAAE;AAAA,QACrF;AAEA,cAAM,MAAM,OAAO,UAAU;AAC7B,kBAAU,GAAG;AAEb,YAAI;AACF,gBAAM,SAAS,MAAM,WAAW,aAAa,OAAO,QAAQ,OAAO,QAAQ;AAC3E,gBAAM,WAAW,GAAG,GAAG,IAAI,OAAO,QAAQ;AAC1C,0BAAgB,UAAU,MAAM;AAChC,iBAAO;AAAA,YACL,SAAS,CAAC;AAAA,cACR,MAAM;AAAA,cACN,MAAM,cAAc,OAAO,QAAQ,MAAM,OAAO,SAAS,MAAM,QAAQ,CAAC,CAAC,WAAW,QAAQ;AAAA,YAC9F,CAAC;AAAA,UACH;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,oBAAqB,IAAc,OAAO,GAAG,CAAC;AAAA,UAChF;AAAA,QACF;AAAA,MACF;AAAA,IACF,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAGvC,QAAI,gBAAgB;AAAA,MAClB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,MACb,SAAS,MAAM;AACb,cAAM,oBAAoB,YAAY,yBAAyB,KAAK;AACpE,cAAM,iBAAiB,YAAY,YAAY,IAC1C,oBAAoB,2CAAoC,qBACzD;AAEJ,eAAO;AAAA,UACL,MAAM;AAAA,YACN;AAAA,YACA,eAAe,IAAI,YAAY,kBAAkB;AAAA,YACjD,eAAe,cAAc,sBAAsB;AAAA,YACnD,eAAe,cAAc;AAAA,YAC7B,eAAe,mBAAmB,IAAI,mBAAmB,uBAAuB,CAAC,IAAI,QAAQ,IAAI;AAAA,YACjG,sBAAsB,eAAe,mBAAmB,KAAK;AAAA,YAC7D,uBAAuB,oBAAoB,oBAAoB,KAAK;AAAA,YACpE,eAAe,aAAa,IAAI;AAAA,YAChC,GAAG,CAAC,GAAG,aAAa,OAAO,CAAC,EAAE;AAAA,cAC5B,CAAC,MAAM,YAAO,EAAE,OAAO,MAAM,GAAG,CAAC,CAAC,WAAM,EAAE,KAAK,UAAU,EAAE,IAAI;AAAA,YACjE;AAAA,UACA,EACG,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,QACd;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
|
|
6
6
|
"names": ["info"]
|
|
7
7
|
}
|