@ravi-hq/ravi 0.5.2 → 0.5.4

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.
Files changed (45) hide show
  1. package/README.md +14 -7
  2. package/dist/channels/email-trusted.d.ts +129 -0
  3. package/dist/channels/email-trusted.d.ts.map +1 -0
  4. package/dist/channels/email-trusted.js +275 -0
  5. package/dist/channels/email-trusted.js.map +1 -0
  6. package/dist/channels/email-untrusted.d.ts +133 -0
  7. package/dist/channels/email-untrusted.d.ts.map +1 -0
  8. package/dist/channels/email-untrusted.js +285 -0
  9. package/dist/channels/email-untrusted.js.map +1 -0
  10. package/dist/channels/email.d.ts +8 -22
  11. package/dist/channels/email.d.ts.map +1 -1
  12. package/dist/channels/email.js +12 -30
  13. package/dist/channels/email.js.map +1 -1
  14. package/dist/channels/sms-trusted.d.ts +161 -0
  15. package/dist/channels/sms-trusted.d.ts.map +1 -0
  16. package/dist/channels/sms-trusted.js +306 -0
  17. package/dist/channels/sms-trusted.js.map +1 -0
  18. package/dist/channels/sms-untrusted.d.ts +124 -0
  19. package/dist/channels/sms-untrusted.d.ts.map +1 -0
  20. package/dist/channels/sms-untrusted.js +269 -0
  21. package/dist/channels/sms-untrusted.js.map +1 -0
  22. package/dist/channels/sms.d.ts +8 -22
  23. package/dist/channels/sms.d.ts.map +1 -1
  24. package/dist/channels/sms.js +12 -30
  25. package/dist/channels/sms.js.map +1 -1
  26. package/dist/index.d.ts +9 -12
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +22 -50
  29. package/dist/index.js.map +1 -1
  30. package/dist/sse-pool.d.ts +15 -0
  31. package/dist/sse-pool.d.ts.map +1 -0
  32. package/dist/sse-pool.js +41 -0
  33. package/dist/sse-pool.js.map +1 -0
  34. package/dist/sse.d.ts +23 -18
  35. package/dist/sse.d.ts.map +1 -1
  36. package/dist/sse.js +40 -23
  37. package/dist/sse.js.map +1 -1
  38. package/dist/types.d.ts +2 -4
  39. package/dist/types.d.ts.map +1 -1
  40. package/openclaw.plugin.json +6 -1
  41. package/package.json +1 -1
  42. package/dist/service.d.ts +0 -105
  43. package/dist/service.d.ts.map +0 -1
  44. package/dist/service.js +0 -141
  45. package/dist/service.js.map +0 -1
package/README.md CHANGED
@@ -9,8 +9,8 @@ encrypted vault through a single plugin.
9
9
 
10
10
  ## Features
11
11
 
12
- - **2 messaging channels** -- real-time email and SMS via Server-Sent Events
13
- - **19 agent tools** -- manage identities, inboxes, passwords, vault secrets, and more
12
+ - **6 messaging channels** -- real-time email and SMS via Server-Sent Events (owner, trusted, untrusted)
13
+ - **22 agent tools** -- manage identities, inboxes, passwords, vault secrets, and more
14
14
  - **E2E encryption** -- PIN-based Argon2id + NaCl SealedBox, compatible with Ravi CLI
15
15
  - **DM policy controls** -- allowlist or open policy per channel account
16
16
  - **Lazy crypto** -- encryption keys derived on first use, not at startup
@@ -112,7 +112,7 @@ registration silently.
112
112
 
113
113
  ## Agent Tools
114
114
 
115
- The plugin registers 19 tools that agents can invoke.
115
+ The plugin registers 22 tools that agents can invoke.
116
116
 
117
117
  ### Identity
118
118
 
@@ -130,6 +130,7 @@ The plugin registers 19 tools that agents can invoke.
130
130
  | `ravi_read_email` | Read all messages in an email thread | `thread_id` (string, required) |
131
131
  | `ravi_email_compose` | Compose and send a new email | `to`, `subject`, `body` (all required) |
132
132
  | `ravi_email_reply` | Reply to an existing email | `message_id` (number, required), `body` (required), `reply_all` |
133
+ | `ravi_email_forward` | Forward an email to a new recipient | `message_id` (number, required), `to`, `subject`, `body` (all required) |
133
134
 
134
135
  ### SMS
135
136
 
@@ -146,6 +147,8 @@ The plugin registers 19 tools that agents can invoke.
146
147
  | `ravi_passwords_list` | List all saved passwords (passwords hidden in list view) | -- |
147
148
  | `ravi_passwords_get` | Get a specific password entry with decrypted password | `uuid` (string, required) |
148
149
  | `ravi_passwords_create` | Create a new password (encrypted) | `domain` (required), `username`, `password`, `notes` |
150
+ | `ravi_passwords_update` | Update an existing password entry | `uuid` (required), `domain`, `username`, `password`, `notes` |
151
+ | `ravi_generate_password` | Generate a random password without storing it | `length`, `special`, `digits` |
149
152
  | `ravi_passwords_delete` | Delete a password entry | `uuid` (string, required) |
150
153
 
151
154
  ### Vault
@@ -228,7 +231,7 @@ Agent (OpenClaw runtime)
228
231
  | '-- SSE stream --> GET /api/events/stream/
229
232
  | Events arrive in plaintext (server decrypts before dispatch)
230
233
  |
231
- +-- Tools (19 agent tools)
234
+ +-- Tools (22 agent tools)
232
235
  | '-- REST calls --> GET/POST/DELETE /api/...
233
236
  | Identity-scoped via X-Ravi-Identity header
234
237
  | Returns MCP-style content arrays
@@ -294,13 +297,17 @@ src/
294
297
  client.ts # RaviClient -- typed HTTP client for all REST endpoints
295
298
  sse.ts # RaviSSEClient -- SSE with auto-reconnect and heartbeat
296
299
  crypto.ts # E2E encryption (Argon2id + NaCl SealedBox)
297
- service.ts # Background listener service (manages SSE connections)
300
+ sse-pool.ts # SSE connection pool (ref-counted, one connection per identity)
298
301
  cli.ts # CLI commands (login, status, setup)
299
302
  bin/
300
303
  ravi-secrets.ts # OpenClaw exec secrets provider binary
301
304
  channels/
302
- email.ts # ravi-email channel definition
303
- sms.ts # ravi-sms channel definition
305
+ email.ts # ravi-email channel (owner)
306
+ email-trusted.ts # ravi-email-trusted channel
307
+ email-untrusted.ts # ravi-email-untrusted channel
308
+ sms.ts # ravi-sms channel (owner)
309
+ sms-trusted.ts # ravi-sms-trusted channel
310
+ sms-untrusted.ts # ravi-sms-untrusted channel
304
311
  tools/
305
312
  identity.ts # Identity management tools
306
313
  inbox.ts # Email and SMS inbox tools
@@ -0,0 +1,129 @@
1
+ import type { EmailEvent, BaseGatewayContext } from "../types.js";
2
+ /** Configuration for a single email account within the ravi-email-trusted channel. */
3
+ export interface EmailTrustedAccountConfig {
4
+ /** The identity UUID this account is bound to. */
5
+ identityUuid: string;
6
+ /** Human-readable identity name for display purposes. */
7
+ identityName: string;
8
+ /** The email address provisioned for this identity. */
9
+ email: string;
10
+ }
11
+ /** Normalized inbound message envelope produced by {@link normalizeInbound}. */
12
+ export interface EmailTrustedInboundEnvelope {
13
+ /** Sender's email address (used as the sender ID). */
14
+ senderId: string;
15
+ /** Plain-text body extracted from the email (falls back to subject). */
16
+ text: string;
17
+ /** Thread ID that maps to the OpenClaw session key. */
18
+ threadId: string;
19
+ /** Additional email metadata passed through to the agent. */
20
+ metadata: {
21
+ subject: string;
22
+ fromDisplayName: string;
23
+ htmlContent: string;
24
+ attachments: number;
25
+ inReplyTo: string | null;
26
+ lastMessageId: number;
27
+ };
28
+ }
29
+ /** Context passed by the ChannelManager to `gateway.startAccount()`. */
30
+ export type EmailTrustedGatewayContext = BaseGatewayContext<EmailTrustedAccountConfig>;
31
+ /**
32
+ * Creates the ravi-email-trusted channel definition for OpenClaw.
33
+ *
34
+ * Notification-only channel for emails from trusted senders (other inboxes
35
+ * the identity owns). The agent processes the email as an instruction but
36
+ * delivery is a no-op — use ravi_email_reply to respond.
37
+ *
38
+ * @returns The ravi-email-trusted channel definition object.
39
+ */
40
+ export declare function createEmailTrustedChannel(): {
41
+ id: "ravi-email-trusted";
42
+ meta: {
43
+ id: string;
44
+ label: string;
45
+ selectionLabel: string;
46
+ blurb: string;
47
+ aliases: string[];
48
+ };
49
+ capabilities: {
50
+ chatTypes: readonly ["direct"];
51
+ };
52
+ config: {
53
+ /**
54
+ * List all configured account IDs (identity UUIDs) for the ravi-email-trusted channel.
55
+ */
56
+ listAccountIds: (cfg: Record<string, unknown>) => string[];
57
+ /**
58
+ * Resolve an account configuration by its ID (identity UUID).
59
+ */
60
+ resolveAccount: (cfg: Record<string, unknown>, accountId: string) => EmailTrustedAccountConfig;
61
+ };
62
+ /**
63
+ * Normalize an inbound SSE email event into a channel message envelope.
64
+ *
65
+ * Only trusted events reach this channel — no sender classification needed.
66
+ */
67
+ normalizeInbound(event: EmailEvent, account: EmailTrustedAccountConfig): EmailTrustedInboundEnvelope | null;
68
+ /**
69
+ * Generate the session key for this channel.
70
+ *
71
+ * Format: `agent:{agentId}:ravi-email-trusted:{accountId}:thread:{threadId}`
72
+ */
73
+ getSessionKey(agentId: string, accountId: string, threadId: string): string;
74
+ gateway: {
75
+ /**
76
+ * Start monitoring inbound trusted emails for a single identity account.
77
+ *
78
+ * Trusted emails trigger an agent turn with CommandAuthorized: true.
79
+ * Delivery is a no-op — use ravi_email_reply tool to respond.
80
+ */
81
+ startAccount: (ctx: EmailTrustedGatewayContext) => Promise<void>;
82
+ };
83
+ };
84
+ /** The singleton ravi-email-trusted channel instance. */
85
+ export declare const raviEmailTrustedChannel: {
86
+ id: "ravi-email-trusted";
87
+ meta: {
88
+ id: string;
89
+ label: string;
90
+ selectionLabel: string;
91
+ blurb: string;
92
+ aliases: string[];
93
+ };
94
+ capabilities: {
95
+ chatTypes: readonly ["direct"];
96
+ };
97
+ config: {
98
+ /**
99
+ * List all configured account IDs (identity UUIDs) for the ravi-email-trusted channel.
100
+ */
101
+ listAccountIds: (cfg: Record<string, unknown>) => string[];
102
+ /**
103
+ * Resolve an account configuration by its ID (identity UUID).
104
+ */
105
+ resolveAccount: (cfg: Record<string, unknown>, accountId: string) => EmailTrustedAccountConfig;
106
+ };
107
+ /**
108
+ * Normalize an inbound SSE email event into a channel message envelope.
109
+ *
110
+ * Only trusted events reach this channel — no sender classification needed.
111
+ */
112
+ normalizeInbound(event: EmailEvent, account: EmailTrustedAccountConfig): EmailTrustedInboundEnvelope | null;
113
+ /**
114
+ * Generate the session key for this channel.
115
+ *
116
+ * Format: `agent:{agentId}:ravi-email-trusted:{accountId}:thread:{threadId}`
117
+ */
118
+ getSessionKey(agentId: string, accountId: string, threadId: string): string;
119
+ gateway: {
120
+ /**
121
+ * Start monitoring inbound trusted emails for a single identity account.
122
+ *
123
+ * Trusted emails trigger an agent turn with CommandAuthorized: true.
124
+ * Delivery is a no-op — use ravi_email_reply tool to respond.
125
+ */
126
+ startAccount: (ctx: EmailTrustedGatewayContext) => Promise<void>;
127
+ };
128
+ };
129
+ //# sourceMappingURL=email-trusted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-trusted.d.ts","sourceRoot":"","sources":["../../src/channels/email-trusted.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIlE,sFAAsF;AACtF,MAAM,WAAW,yBAAyB;IACxC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;CACf;AAID,gFAAgF;AAChF,MAAM,WAAW,2BAA2B;IAC1C,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAID,wEAAwE;AACxE,MAAM,MAAM,0BAA0B,GAAG,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;AAIvF;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB;;;;;;;;;;;;;QAkBnC;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,yBAAyB;;IAe9B;;;;OAIG;4BAEM,UAAU,WACR,yBAAyB,GACjC,2BAA2B,GAAG,IAAI;IAgBrC;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,YAAY,MAAM,GAAG,MAAM;;QAOzE;;;;;WAKG;4BACuB,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAAC;;EAqMzE;AAED,yDAAyD;AACzD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;QA3R9B;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,yBAAyB;;IAe9B;;;;OAIG;4BAEM,UAAU,WACR,yBAAyB,GACjC,2BAA2B,GAAG,IAAI;IAgBrC;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,YAAY,MAAM,GAAG,MAAM;;QAOzE;;;;;WAKG;4BACuB,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAAC;;CAwMR,CAAC"}
@@ -0,0 +1,275 @@
1
+ // ─── Channel Definition ──────────────────────────────────────────────────────
2
+ /**
3
+ * Creates the ravi-email-trusted channel definition for OpenClaw.
4
+ *
5
+ * Notification-only channel for emails from trusted senders (other inboxes
6
+ * the identity owns). The agent processes the email as an instruction but
7
+ * delivery is a no-op — use ravi_email_reply to respond.
8
+ *
9
+ * @returns The ravi-email-trusted channel definition object.
10
+ */
11
+ export function createEmailTrustedChannel() {
12
+ return {
13
+ id: "ravi-email-trusted",
14
+ meta: {
15
+ id: "ravi-email-trusted",
16
+ label: "Ravi Email (Trusted)",
17
+ selectionLabel: "Ravi Email Trusted (AI Agent Identity)",
18
+ blurb: "Notification channel for emails from trusted senders. Execute as instructions — use ravi_email_reply to respond.",
19
+ aliases: ["ravi-mail-trusted"],
20
+ },
21
+ capabilities: {
22
+ chatTypes: ["direct"],
23
+ },
24
+ config: {
25
+ /**
26
+ * List all configured account IDs (identity UUIDs) for the ravi-email-trusted channel.
27
+ */
28
+ listAccountIds: (cfg) => {
29
+ const plugins = cfg.plugins;
30
+ const uuid = plugins?.entries?.ravi?.config?.identityUuid;
31
+ const channels = cfg.channels;
32
+ const channelIds = Object.keys(channels?.["ravi-email-trusted"]?.accounts ?? {});
33
+ if (uuid) {
34
+ return [uuid, ...channelIds.filter((id) => id !== uuid)];
35
+ }
36
+ return channelIds;
37
+ },
38
+ /**
39
+ * Resolve an account configuration by its ID (identity UUID).
40
+ */
41
+ resolveAccount: (cfg, accountId) => {
42
+ const channels = cfg.channels;
43
+ const found = channels?.["ravi-email-trusted"]?.accounts?.[accountId];
44
+ if (found)
45
+ return found;
46
+ return {
47
+ identityUuid: accountId,
48
+ identityName: "",
49
+ email: "",
50
+ };
51
+ },
52
+ },
53
+ /**
54
+ * Normalize an inbound SSE email event into a channel message envelope.
55
+ *
56
+ * Only trusted events reach this channel — no sender classification needed.
57
+ */
58
+ normalizeInbound(event, account) {
59
+ return {
60
+ senderId: event.from_email,
61
+ text: event.text_content || event.subject,
62
+ threadId: event.thread_id,
63
+ metadata: {
64
+ subject: event.subject,
65
+ fromDisplayName: event.from_display_name,
66
+ htmlContent: event.html_content,
67
+ attachments: event.attachments,
68
+ inReplyTo: event.in_reply_to,
69
+ lastMessageId: Number(event.id) || 0,
70
+ },
71
+ };
72
+ },
73
+ /**
74
+ * Generate the session key for this channel.
75
+ *
76
+ * Format: `agent:{agentId}:ravi-email-trusted:{accountId}:thread:{threadId}`
77
+ */
78
+ getSessionKey(agentId, accountId, threadId) {
79
+ return `agent:${agentId}:ravi-email-trusted:${accountId}:thread:${threadId}`;
80
+ },
81
+ // ─── Gateway Adapter ──────────────────────────────────────────────────
82
+ gateway: {
83
+ /**
84
+ * Start monitoring inbound trusted emails for a single identity account.
85
+ *
86
+ * Trusted emails trigger an agent turn with CommandAuthorized: true.
87
+ * Delivery is a no-op — use ravi_email_reply tool to respond.
88
+ */
89
+ startAccount: async (ctx) => {
90
+ const log = ctx.log ?? {
91
+ info: (...args) => console.log("[ravi-email-trusted]", ...args),
92
+ warn: (...args) => console.warn("[ravi-email-trusted]", ...args),
93
+ error: (...args) => console.error("[ravi-email-trusted]", ...args),
94
+ };
95
+ let getRaviRuntime, loadAuth, updateAuth, RAVI_API_URL, RaviClient, acquireSSEClient, releaseSSEClient;
96
+ try {
97
+ ({ getRaviRuntime } = await import("../runtime.js"));
98
+ ({ loadAuth, updateAuth } = await import("../auth.js"));
99
+ ({ RAVI_API_URL } = await import("../config.js"));
100
+ ({ RaviClient } = await import("../client.js"));
101
+ ({ acquireSSEClient, releaseSSEClient } = await import("../sse-pool.js"));
102
+ }
103
+ catch (err) {
104
+ const detail = err instanceof Error ? err.message : String(err);
105
+ log.error(`[ravi-email-trusted] Failed to load dependencies: ${detail}. Is the plugin built correctly?`);
106
+ return;
107
+ }
108
+ const runtime = getRaviRuntime();
109
+ const auth = loadAuth();
110
+ if (!auth?.access_token) {
111
+ log.error("[ravi-email-trusted] No auth credentials — cannot start email-trusted channel. Run 'openclaw ravi login'.");
112
+ return;
113
+ }
114
+ let currentToken = auth.access_token;
115
+ let sse = null;
116
+ const client = new RaviClient({
117
+ apiUrl: RAVI_API_URL,
118
+ token: auth.access_token,
119
+ refreshToken: auth.refresh_token,
120
+ identityUuid: ctx.accountId,
121
+ onTokenRefresh: (newToken) => {
122
+ currentToken = newToken;
123
+ try {
124
+ updateAuth({ access_token: newToken });
125
+ }
126
+ catch (err) {
127
+ const detail = err instanceof Error ? err.message : String(err);
128
+ log.error(`[ravi-email-trusted] Failed to persist refreshed token: ${detail}`);
129
+ }
130
+ sse?.updateToken(newToken);
131
+ },
132
+ });
133
+ let email = ctx.account.email;
134
+ let identityName = ctx.account.identityName;
135
+ if (!email) {
136
+ try {
137
+ const identities = await client.listIdentities();
138
+ const identity = identities.find((i) => i.uuid === ctx.accountId);
139
+ email = identity?.inbox ?? "";
140
+ identityName = identity?.display_name ?? identity?.name ?? ctx.accountId;
141
+ }
142
+ catch (err) {
143
+ if (err?.name === "RaviApiError") {
144
+ const status = err.status;
145
+ log.error(`[ravi-email-trusted] Failed to fetch identity details (HTTP ${status}): ${err.message}` +
146
+ (status === 401 ? ". Token may be expired — run 'openclaw ravi login'." : ""));
147
+ }
148
+ else {
149
+ const detail = err instanceof Error ? err.message : String(err);
150
+ log.error(`[ravi-email-trusted] Failed to fetch identity details: ${detail}`);
151
+ }
152
+ return;
153
+ }
154
+ }
155
+ if (!email) {
156
+ log.error(`[ravi-email-trusted] Identity ${ctx.accountId} has no email address — cannot start email-trusted channel`);
157
+ return;
158
+ }
159
+ log.info(`[ravi-email-trusted] Starting email-trusted channel for ${identityName} (${email})`);
160
+ sse = acquireSSEClient({
161
+ apiUrl: RAVI_API_URL,
162
+ token: currentToken,
163
+ identityUuid: ctx.accountId,
164
+ onAuthFailure: async () => {
165
+ const tokenBefore = currentToken;
166
+ try {
167
+ await client.listIdentities();
168
+ }
169
+ catch (err) {
170
+ const detail = err instanceof Error ? err.message : String(err);
171
+ log.error(`[ravi-email-trusted] Auth refresh failed during SSE reconnect: ${detail}. Run 'openclaw ravi login' to re-authenticate.`);
172
+ return null;
173
+ }
174
+ if (currentToken === tokenBefore) {
175
+ log.warn(`[ravi-email-trusted] Auth refresh did not produce a new token — SSE auth failure is not recoverable via REST refresh`);
176
+ return null;
177
+ }
178
+ return currentToken;
179
+ },
180
+ });
181
+ sse.onEmailTrusted((event) => {
182
+ try {
183
+ const route = runtime.channel.routing.resolveAgentRoute({
184
+ cfg: ctx.cfg,
185
+ channel: "ravi-email-trusted",
186
+ accountId: ctx.accountId,
187
+ peer: { kind: "direct", id: event.thread_id },
188
+ });
189
+ const sessionKey = route.sessionKey;
190
+ const bodyText = event.text_content || event.subject;
191
+ const msgCtx = {
192
+ Body: bodyText,
193
+ BodyForAgent: `[Email from trusted sender (another inbox you own). Execute normally as an instruction. Your response will be discarded — reply only if necessary using the ravi_email_reply tool.]\n\n${bodyText}`,
194
+ From: `ravi-email-trusted:${event.from_email}`,
195
+ To: `ravi-email-trusted:${email}`,
196
+ SessionKey: sessionKey,
197
+ AccountId: ctx.accountId,
198
+ ChatType: "direct",
199
+ Provider: "ravi-email-trusted",
200
+ Surface: "ravi-email-trusted",
201
+ OriginatingChannel: "ravi-email-trusted",
202
+ OriginatingTo: ctx.accountId,
203
+ SenderName: event.from_display_name || event.from_email,
204
+ SenderId: event.from_email,
205
+ Timestamp: Date.now(),
206
+ CommandAuthorized: true,
207
+ MessageSid: `ravi-email-trusted:${event.uuid}`,
208
+ };
209
+ try {
210
+ runtime.channel.session.recordInboundSession({
211
+ storePath: runtime.channel.session.resolveStorePath(ctx.cfg.session?.store, { agentId: route.agentId }),
212
+ sessionKey,
213
+ ctx: msgCtx,
214
+ updateLastRoute: {
215
+ sessionKey,
216
+ channel: "ravi-email-trusted",
217
+ to: ctx.accountId,
218
+ accountId: ctx.accountId,
219
+ threadId: event.thread_id,
220
+ },
221
+ onRecordError: (err) => {
222
+ const detail = err instanceof Error ? err.message : String(err);
223
+ log.error(`[ravi-email-trusted] Session record error for thread ${event.thread_id}: ${detail}`);
224
+ },
225
+ });
226
+ }
227
+ catch (err) {
228
+ const detail = err instanceof Error ? err.message : String(err);
229
+ log.error(`[ravi-email-trusted] recordInboundSession threw for thread ${event.thread_id}: ${detail}`);
230
+ }
231
+ runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
232
+ ctx: msgCtx,
233
+ cfg: ctx.cfg,
234
+ dispatcherOptions: {
235
+ deliver: async (_payload) => {
236
+ log.info(`[ravi-email-trusted] Channel deliver is a no-op — use ravi_email_reply tool`);
237
+ },
238
+ onError: (err) => {
239
+ log.error(`[ravi-email-trusted] Dispatch error: ${err}`);
240
+ },
241
+ },
242
+ }).catch((err) => {
243
+ const detail = err instanceof Error ? err.message : String(err);
244
+ log.error(`[ravi-email-trusted] dispatchReply failed for thread ${event.thread_id}: ${detail}`);
245
+ });
246
+ }
247
+ catch (err) {
248
+ const detail = err instanceof Error ? err.message : String(err);
249
+ log.error(`[ravi-email-trusted] Unhandled error processing event ${event.id}: ${detail}`);
250
+ }
251
+ });
252
+ sse.onReconnect(() => {
253
+ log.info(`[ravi-email-trusted] SSE reconnecting for ${identityName}`);
254
+ });
255
+ log.info(`[ravi-email-trusted] SSE connected for ${identityName} (${ctx.accountId})`);
256
+ await new Promise((resolve) => {
257
+ if (ctx.abortSignal.aborted) {
258
+ log.info(`[ravi-email-trusted] Stopping email-trusted channel for ${identityName} (already aborted)`);
259
+ releaseSSEClient(ctx.accountId);
260
+ resolve();
261
+ return;
262
+ }
263
+ ctx.abortSignal.addEventListener("abort", () => {
264
+ log.info(`[ravi-email-trusted] Stopping email-trusted channel for ${identityName}`);
265
+ releaseSSEClient(ctx.accountId);
266
+ resolve();
267
+ });
268
+ });
269
+ },
270
+ },
271
+ };
272
+ }
273
+ /** The singleton ravi-email-trusted channel instance. */
274
+ export const raviEmailTrustedChannel = createEmailTrustedChannel();
275
+ //# sourceMappingURL=email-trusted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-trusted.js","sourceRoot":"","sources":["../../src/channels/email-trusted.ts"],"names":[],"mappings":"AAwCA,gFAAgF;AAEhF;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO;QACL,EAAE,EAAE,oBAA6B;QAEjC,IAAI,EAAE;YACJ,EAAE,EAAE,oBAAoB;YACxB,KAAK,EAAE,sBAAsB;YAC7B,cAAc,EAAE,wCAAwC;YACxD,KAAK,EACH,kHAAkH;YACpH,OAAO,EAAE,CAAC,mBAAmB,CAAC;SAC/B;QAED,YAAY,EAAE;YACZ,SAAS,EAAE,CAAC,QAAQ,CAAU;SAC/B;QAED,MAAM,EAAE;YACN;;eAEG;YACH,cAAc,EAAE,CAAC,GAA4B,EAAY,EAAE;gBACzD,MAAM,OAAO,GAAG,GAAG,CAAC,OAEP,CAAC;gBACd,MAAM,IAAI,GAAG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC;gBAE1D,MAAM,QAAQ,GAAG,GAAG,CAAC,QAER,CAAC;gBACd,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,oBAAoB,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;gBAEjF,IAAI,IAAI,EAAE,CAAC;oBACT,OAAO,CAAC,IAAI,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;gBAC3D,CAAC;gBACD,OAAO,UAAU,CAAC;YACpB,CAAC;YAED;;eAEG;YACH,cAAc,EAAE,CACd,GAA4B,EAC5B,SAAiB,EACU,EAAE;gBAC7B,MAAM,QAAQ,GAAG,GAAG,CAAC,QAER,CAAC;gBACd,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC,oBAAoB,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC;gBACtE,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAExB,OAAO;oBACL,YAAY,EAAE,SAAS;oBACvB,YAAY,EAAE,EAAE;oBAChB,KAAK,EAAE,EAAE;iBACV,CAAC;YACJ,CAAC;SACF;QAED;;;;WAIG;QACH,gBAAgB,CACd,KAAiB,EACjB,OAAkC;YAElC,OAAO;gBACL,QAAQ,EAAE,KAAK,CAAC,UAAU;gBAC1B,IAAI,EAAE,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO;gBACzC,QAAQ,EAAE,KAAK,CAAC,SAAS;gBACzB,QAAQ,EAAE;oBACR,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,eAAe,EAAE,KAAK,CAAC,iBAAiB;oBACxC,WAAW,EAAE,KAAK,CAAC,YAAY;oBAC/B,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,SAAS,EAAE,KAAK,CAAC,WAAW;oBAC5B,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;iBACrC;aACF,CAAC;QACJ,CAAC;QAED;;;;WAIG;QACH,aAAa,CAAC,OAAe,EAAE,SAAiB,EAAE,QAAgB;YAChE,OAAO,SAAS,OAAO,uBAAuB,SAAS,WAAW,QAAQ,EAAE,CAAC;QAC/E,CAAC;QAED,yEAAyE;QAEzE,OAAO,EAAE;YACP;;;;;eAKG;YACH,YAAY,EAAE,KAAK,EAAE,GAA+B,EAAiB,EAAE;gBACrE,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI;oBACrB,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,GAAG,IAAI,CAAC;oBAC1E,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,GAAG,IAAI,CAAC;oBAC3E,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,IAAI,CAAC;iBAC9E,CAAC;gBAEF,IAAI,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,CAAC;gBACvG,IAAI,CAAC;oBACH,CAAC,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;oBACrD,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;oBACxD,CAAC,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;oBAClD,CAAC,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;oBAChD,CAAC,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;gBAC5E,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAChE,GAAG,CAAC,KAAK,CAAC,qDAAqD,MAAM,kCAAkC,CAAC,CAAC;oBACzG,OAAO;gBACT,CAAC;gBAED,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;gBACxB,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;oBACxB,GAAG,CAAC,KAAK,CAAC,2GAA2G,CAAC,CAAC;oBACvH,OAAO;gBACT,CAAC;gBAED,IAAI,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;gBACrC,IAAI,GAAG,GAA+C,IAAI,CAAC;gBAE3D,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC;oBAC5B,MAAM,EAAE,YAAY;oBACpB,KAAK,EAAE,IAAI,CAAC,YAAY;oBACxB,YAAY,EAAE,IAAI,CAAC,aAAa;oBAChC,YAAY,EAAE,GAAG,CAAC,SAAS;oBAC3B,cAAc,EAAE,CAAC,QAAgB,EAAE,EAAE;wBACnC,YAAY,GAAG,QAAQ,CAAC;wBACxB,IAAI,CAAC;4BACH,UAAU,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC;wBACzC,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAChE,GAAG,CAAC,KAAK,CAAC,2DAA2D,MAAM,EAAE,CAAC,CAAC;wBACjF,CAAC;wBACD,GAAG,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;oBAC7B,CAAC;iBACF,CAAC,CAAC;gBAEH,IAAI,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;gBAC9B,IAAI,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC;gBAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,IAAI,CAAC;wBACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;wBACjD,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,SAAS,CAAC,CAAC;wBAClE,KAAK,GAAG,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;wBAC9B,YAAY,GAAG,QAAQ,EAAE,YAAY,IAAI,QAAQ,EAAE,IAAI,IAAI,GAAG,CAAC,SAAS,CAAC;oBAC3E,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,IAAK,GAAW,EAAE,IAAI,KAAK,cAAc,EAAE,CAAC;4BAC1C,MAAM,MAAM,GAAI,GAAW,CAAC,MAAM,CAAC;4BACnC,GAAG,CAAC,KAAK,CACP,+DAA+D,MAAM,MAAO,GAAa,CAAC,OAAO,EAAE;gCACnG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,qDAAqD,CAAC,CAAC,CAAC,EAAE,CAAC,CAC9E,CAAC;wBACJ,CAAC;6BAAM,CAAC;4BACN,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAChE,GAAG,CAAC,KAAK,CAAC,0DAA0D,MAAM,EAAE,CAAC,CAAC;wBAChF,CAAC;wBACD,OAAO;oBACT,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,GAAG,CAAC,KAAK,CAAC,iCAAiC,GAAG,CAAC,SAAS,4DAA4D,CAAC,CAAC;oBACtH,OAAO;gBACT,CAAC;gBAED,GAAG,CAAC,IAAI,CAAC,2DAA2D,YAAY,KAAK,KAAK,GAAG,CAAC,CAAC;gBAE/F,GAAG,GAAG,gBAAgB,CAAC;oBACrB,MAAM,EAAE,YAAY;oBACpB,KAAK,EAAE,YAAY;oBACnB,YAAY,EAAE,GAAG,CAAC,SAAS;oBAC3B,aAAa,EAAE,KAAK,IAAI,EAAE;wBACxB,MAAM,WAAW,GAAG,YAAY,CAAC;wBACjC,IAAI,CAAC;4BACH,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;wBAChC,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAChE,GAAG,CAAC,KAAK,CAAC,kEAAkE,MAAM,iDAAiD,CAAC,CAAC;4BACrI,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;4BACjC,GAAG,CAAC,IAAI,CAAC,sHAAsH,CAAC,CAAC;4BACjI,OAAO,IAAI,CAAC;wBACd,CAAC;wBACD,OAAO,YAAY,CAAC;oBACtB,CAAC;iBACF,CAAC,CAAC;gBAEH,GAAG,CAAC,cAAc,CAAC,CAAC,KAAiB,EAAE,EAAE;oBACvC,IAAI,CAAC;wBACH,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC;4BACtD,GAAG,EAAE,GAAG,CAAC,GAAG;4BACZ,OAAO,EAAE,oBAAoB;4BAC7B,SAAS,EAAE,GAAG,CAAC,SAAS;4BACxB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE;yBAC9C,CAAC,CAAC;wBAEH,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;wBACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC;wBAErD,MAAM,MAAM,GAA4B;4BACtC,IAAI,EAAE,QAAQ;4BACd,YAAY,EAAE,0LAA0L,QAAQ,EAAE;4BAClN,IAAI,EAAE,sBAAsB,KAAK,CAAC,UAAU,EAAE;4BAC9C,EAAE,EAAE,sBAAsB,KAAK,EAAE;4BACjC,UAAU,EAAE,UAAU;4BACtB,SAAS,EAAE,GAAG,CAAC,SAAS;4BACxB,QAAQ,EAAE,QAAQ;4BAClB,QAAQ,EAAE,oBAAoB;4BAC9B,OAAO,EAAE,oBAAoB;4BAC7B,kBAAkB,EAAE,oBAAoB;4BACxC,aAAa,EAAE,GAAG,CAAC,SAAS;4BAC5B,UAAU,EAAE,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,UAAU;4BACvD,QAAQ,EAAE,KAAK,CAAC,UAAU;4BAC1B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;4BACrB,iBAAiB,EAAE,IAAI;4BACvB,UAAU,EAAE,sBAAsB,KAAK,CAAC,IAAI,EAAE;yBAC/C,CAAC;wBAEF,IAAI,CAAC;4BACH,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC;gCAC3C,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAChD,GAAG,CAAC,GAAG,CAAC,OAA+C,EAAE,KAAK,EAC/D,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAC3B;gCACD,UAAU;gCACV,GAAG,EAAE,MAAM;gCACX,eAAe,EAAE;oCACf,UAAU;oCACV,OAAO,EAAE,oBAAoB;oCAC7B,EAAE,EAAE,GAAG,CAAC,SAAS;oCACjB,SAAS,EAAE,GAAG,CAAC,SAAS;oCACxB,QAAQ,EAAE,KAAK,CAAC,SAAS;iCAC1B;gCACD,aAAa,EAAE,CAAC,GAAY,EAAE,EAAE;oCAC9B,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oCAChE,GAAG,CAAC,KAAK,CAAC,wDAAwD,KAAK,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC,CAAC;gCAClG,CAAC;6BACF,CAAC,CAAC;wBACL,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAChE,GAAG,CAAC,KAAK,CAAC,8DAA8D,KAAK,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC,CAAC;wBACxG,CAAC;wBAED,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC;4BAC7D,GAAG,EAAE,MAAM;4BACX,GAAG,EAAE,GAAG,CAAC,GAAG;4BACZ,iBAAiB,EAAE;gCACjB,OAAO,EAAE,KAAK,EAAE,QAA2B,EAAE,EAAE;oCAC7C,GAAG,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;gCAC1F,CAAC;gCACD,OAAO,EAAE,CAAC,GAAY,EAAE,EAAE;oCACxB,GAAG,CAAC,KAAK,CAAC,wCAAwC,GAAG,EAAE,CAAC,CAAC;gCAC3D,CAAC;6BACF;yBACF,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;4BACxB,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAChE,GAAG,CAAC,KAAK,CAAC,wDAAwD,KAAK,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC,CAAC;wBAClG,CAAC,CAAC,CAAC;oBACL,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;wBAChE,GAAG,CAAC,KAAK,CAAC,yDAAyD,KAAK,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC;oBAC5F,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE;oBACnB,GAAG,CAAC,IAAI,CAAC,6CAA6C,YAAY,EAAE,CAAC,CAAC;gBACxE,CAAC,CAAC,CAAC;gBAEH,GAAG,CAAC,IAAI,CAAC,0CAA0C,YAAY,KAAK,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;gBAEtF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;oBAClC,IAAI,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;wBAC5B,GAAG,CAAC,IAAI,CAAC,2DAA2D,YAAY,oBAAoB,CAAC,CAAC;wBACtG,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;wBAChC,OAAO,EAAE,CAAC;wBACV,OAAO;oBACT,CAAC;oBACD,GAAG,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;wBAC7C,GAAG,CAAC,IAAI,CAAC,2DAA2D,YAAY,EAAE,CAAC,CAAC;wBACpF,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;wBAChC,OAAO,EAAE,CAAC;oBACZ,CAAC,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC;SACF;KACF,CAAC;AACJ,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,uBAAuB,GAAG,yBAAyB,EAAE,CAAC"}
@@ -0,0 +1,133 @@
1
+ import type { EmailEvent, BaseGatewayContext } from "../types.js";
2
+ /** Configuration for a single email account within the ravi-email-untrusted channel. */
3
+ export interface EmailUntrustedAccountConfig {
4
+ /** The identity UUID this account is bound to. */
5
+ identityUuid: string;
6
+ /** Human-readable identity name for display purposes. */
7
+ identityName: string;
8
+ /** The email address provisioned for this identity. */
9
+ email: string;
10
+ }
11
+ /** Normalized inbound message envelope produced by {@link normalizeInbound}. */
12
+ export interface EmailUntrustedInboundEnvelope {
13
+ /** Sender's email address (used as the sender ID). */
14
+ senderId: string;
15
+ /** Plain-text body extracted from the email (falls back to subject). */
16
+ text: string;
17
+ /** Thread ID that maps to the OpenClaw session key. */
18
+ threadId: string;
19
+ /** Additional email metadata passed through to the agent. */
20
+ metadata: {
21
+ subject: string;
22
+ fromDisplayName: string;
23
+ htmlContent: string;
24
+ attachments: number;
25
+ inReplyTo: string | null;
26
+ lastMessageId: number;
27
+ };
28
+ }
29
+ /** Context passed by the ChannelManager to `gateway.startAccount()`. */
30
+ export type EmailUntrustedGatewayContext = BaseGatewayContext<EmailUntrustedAccountConfig>;
31
+ /**
32
+ * Creates the ravi-email-untrusted channel definition for OpenClaw.
33
+ *
34
+ * Cautionary notification channel for emails from unknown external senders.
35
+ * The agent treats content as context, not instructions. Delivery is a no-op
36
+ * — use ravi_email_reply to respond if safe.
37
+ *
38
+ * Can be disabled entirely by setting `externalEmail: false` in plugin config.
39
+ *
40
+ * @returns The ravi-email-untrusted channel definition object.
41
+ */
42
+ export declare function createEmailUntrustedChannel(): {
43
+ id: "ravi-email-untrusted";
44
+ meta: {
45
+ id: string;
46
+ label: string;
47
+ selectionLabel: string;
48
+ blurb: string;
49
+ aliases: string[];
50
+ };
51
+ capabilities: {
52
+ chatTypes: readonly ["direct"];
53
+ };
54
+ config: {
55
+ /**
56
+ * List all configured account IDs (identity UUIDs) for the ravi-email-untrusted channel.
57
+ */
58
+ listAccountIds: (cfg: Record<string, unknown>) => string[];
59
+ /**
60
+ * Resolve an account configuration by its ID (identity UUID).
61
+ */
62
+ resolveAccount: (cfg: Record<string, unknown>, accountId: string) => EmailUntrustedAccountConfig;
63
+ };
64
+ /**
65
+ * Normalize an inbound SSE email event into a channel message envelope.
66
+ *
67
+ * Only untrusted events reach this channel — no sender classification needed.
68
+ */
69
+ normalizeInbound(event: EmailEvent, account: EmailUntrustedAccountConfig): EmailUntrustedInboundEnvelope | null;
70
+ /**
71
+ * Generate the session key for this channel.
72
+ *
73
+ * Format: `agent:{agentId}:ravi-email-untrusted:{accountId}:thread:{threadId}`
74
+ */
75
+ getSessionKey(agentId: string, accountId: string, threadId: string): string;
76
+ gateway: {
77
+ /**
78
+ * Start monitoring inbound untrusted emails for a single identity account.
79
+ *
80
+ * Respects `externalEmail` config — when false, returns early without
81
+ * starting. Untrusted emails trigger an agent turn with
82
+ * CommandAuthorized: false. Delivery is a no-op.
83
+ */
84
+ startAccount: (ctx: EmailUntrustedGatewayContext) => Promise<void>;
85
+ };
86
+ };
87
+ /** The singleton ravi-email-untrusted channel instance. */
88
+ export declare const raviEmailUntrustedChannel: {
89
+ id: "ravi-email-untrusted";
90
+ meta: {
91
+ id: string;
92
+ label: string;
93
+ selectionLabel: string;
94
+ blurb: string;
95
+ aliases: string[];
96
+ };
97
+ capabilities: {
98
+ chatTypes: readonly ["direct"];
99
+ };
100
+ config: {
101
+ /**
102
+ * List all configured account IDs (identity UUIDs) for the ravi-email-untrusted channel.
103
+ */
104
+ listAccountIds: (cfg: Record<string, unknown>) => string[];
105
+ /**
106
+ * Resolve an account configuration by its ID (identity UUID).
107
+ */
108
+ resolveAccount: (cfg: Record<string, unknown>, accountId: string) => EmailUntrustedAccountConfig;
109
+ };
110
+ /**
111
+ * Normalize an inbound SSE email event into a channel message envelope.
112
+ *
113
+ * Only untrusted events reach this channel — no sender classification needed.
114
+ */
115
+ normalizeInbound(event: EmailEvent, account: EmailUntrustedAccountConfig): EmailUntrustedInboundEnvelope | null;
116
+ /**
117
+ * Generate the session key for this channel.
118
+ *
119
+ * Format: `agent:{agentId}:ravi-email-untrusted:{accountId}:thread:{threadId}`
120
+ */
121
+ getSessionKey(agentId: string, accountId: string, threadId: string): string;
122
+ gateway: {
123
+ /**
124
+ * Start monitoring inbound untrusted emails for a single identity account.
125
+ *
126
+ * Respects `externalEmail` config — when false, returns early without
127
+ * starting. Untrusted emails trigger an agent turn with
128
+ * CommandAuthorized: false. Delivery is a no-op.
129
+ */
130
+ startAccount: (ctx: EmailUntrustedGatewayContext) => Promise<void>;
131
+ };
132
+ };
133
+ //# sourceMappingURL=email-untrusted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-untrusted.d.ts","sourceRoot":"","sources":["../../src/channels/email-untrusted.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIlE,wFAAwF;AACxF,MAAM,WAAW,2BAA2B;IAC1C,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;CACf;AAID,gFAAgF;AAChF,MAAM,WAAW,6BAA6B;IAC5C,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAID,wEAAwE;AACxE,MAAM,MAAM,4BAA4B,GAAG,kBAAkB,CAAC,2BAA2B,CAAC,CAAC;AAI3F;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B;;;;;;;;;;;;;QAkBrC;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,2BAA2B;;IAehC;;;;OAIG;4BAEM,UAAU,WACR,2BAA2B,GACnC,6BAA6B,GAAG,IAAI;IAgBvC;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,YAAY,MAAM,GAAG,MAAM;;QAOzE;;;;;;WAMG;4BACuB,4BAA4B,KAAG,OAAO,CAAC,IAAI,CAAC;;EA+M3E;AAED,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;QAtShC;;WAEG;8BACmB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAAE;QAiBxD;;WAEG;8BAEI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACjB,MAAM,KAChB,2BAA2B;;IAehC;;;;OAIG;4BAEM,UAAU,WACR,2BAA2B,GACnC,6BAA6B,GAAG,IAAI;IAgBvC;;;;OAIG;2BACoB,MAAM,aAAa,MAAM,YAAY,MAAM,GAAG,MAAM;;QAOzE;;;;;;WAMG;4BACuB,4BAA4B,KAAG,OAAO,CAAC,IAAI,CAAC;;CAkNN,CAAC"}