@runcore-sh/runcore 0.1.8 → 0.1.10
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/dist/access/manifest.d.ts +59 -0
- package/dist/access/manifest.d.ts.map +1 -0
- package/dist/access/manifest.js +251 -0
- package/dist/access/manifest.js.map +1 -0
- package/dist/activity/log.d.ts +1 -1
- package/dist/activity/log.d.ts.map +1 -1
- package/dist/agents/autonomous.d.ts.map +1 -1
- package/dist/agents/autonomous.js +38 -0
- package/dist/agents/autonomous.js.map +1 -1
- package/dist/agents/governance.d.ts +70 -0
- package/dist/agents/governance.d.ts.map +1 -0
- package/dist/agents/governance.js +220 -0
- package/dist/agents/governance.js.map +1 -0
- package/dist/agents/governed-spawn.d.ts +83 -0
- package/dist/agents/governed-spawn.d.ts.map +1 -0
- package/dist/agents/governed-spawn.js +186 -0
- package/dist/agents/governed-spawn.js.map +1 -0
- package/dist/agents/heartbeat.d.ts +91 -0
- package/dist/agents/heartbeat.d.ts.map +1 -0
- package/dist/agents/heartbeat.js +323 -0
- package/dist/agents/heartbeat.js.map +1 -0
- package/dist/agents/index.d.ts +4 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +6 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/spawn-policy.d.ts +45 -0
- package/dist/agents/spawn-policy.d.ts.map +1 -0
- package/dist/agents/spawn-policy.js +202 -0
- package/dist/agents/spawn-policy.js.map +1 -0
- package/dist/alert.d.ts +16 -0
- package/dist/alert.d.ts.map +1 -0
- package/dist/alert.js +70 -0
- package/dist/alert.js.map +1 -0
- package/dist/cli.js +261 -32
- package/dist/cli.js.map +1 -1
- package/dist/credentials/store.d.ts +1 -1
- package/dist/credentials/store.d.ts.map +1 -1
- package/dist/credentials/store.js +14 -3
- package/dist/credentials/store.js.map +1 -1
- package/dist/crystallizer.d.ts +56 -0
- package/dist/crystallizer.d.ts.map +1 -0
- package/dist/crystallizer.js +159 -0
- package/dist/crystallizer.js.map +1 -0
- package/dist/distiller.d.ts +48 -0
- package/dist/distiller.d.ts.map +1 -0
- package/dist/distiller.js +140 -0
- package/dist/distiller.js.map +1 -0
- package/dist/files/deep-index.d.ts +59 -0
- package/dist/files/deep-index.d.ts.map +1 -0
- package/dist/files/deep-index.js +337 -0
- package/dist/files/deep-index.js.map +1 -0
- package/dist/files/import.d.ts +44 -0
- package/dist/files/import.d.ts.map +1 -0
- package/dist/files/import.js +213 -0
- package/dist/files/import.js.map +1 -0
- package/dist/files/index-local.d.ts +37 -0
- package/dist/files/index-local.d.ts.map +1 -0
- package/dist/files/index-local.js +198 -0
- package/dist/files/index-local.js.map +1 -0
- package/dist/google/auth.d.ts +2 -0
- package/dist/google/auth.d.ts.map +1 -1
- package/dist/google/auth.js +2 -0
- package/dist/google/auth.js.map +1 -1
- package/dist/integrations/gate.d.ts +40 -0
- package/dist/integrations/gate.d.ts.map +1 -0
- package/dist/integrations/gate.js +100 -0
- package/dist/integrations/gate.js.map +1 -0
- package/dist/lib/audit.d.ts +43 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +120 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/brain-io.d.ts.map +1 -1
- package/dist/lib/brain-io.js +52 -0
- package/dist/lib/brain-io.js.map +1 -1
- package/dist/lib/dpapi.d.ts +14 -0
- package/dist/lib/dpapi.d.ts.map +1 -0
- package/dist/lib/dpapi.js +104 -0
- package/dist/lib/dpapi.js.map +1 -0
- package/dist/lib/glob-match.d.ts +22 -0
- package/dist/lib/glob-match.d.ts.map +1 -0
- package/dist/lib/glob-match.js +64 -0
- package/dist/lib/glob-match.js.map +1 -0
- package/dist/lib/locked.d.ts +40 -0
- package/dist/lib/locked.d.ts.map +1 -0
- package/dist/lib/locked.js +130 -0
- package/dist/lib/locked.js.map +1 -0
- package/dist/llm/complete.d.ts.map +1 -1
- package/dist/llm/complete.js +5 -2
- package/dist/llm/complete.js.map +1 -1
- package/dist/llm/fetch-guard.d.ts +16 -0
- package/dist/llm/fetch-guard.d.ts.map +1 -0
- package/dist/llm/fetch-guard.js +61 -0
- package/dist/llm/fetch-guard.js.map +1 -0
- package/dist/llm/guard.d.ts +40 -0
- package/dist/llm/guard.d.ts.map +1 -0
- package/dist/llm/guard.js +88 -0
- package/dist/llm/guard.js.map +1 -0
- package/dist/llm/membrane.d.ts +46 -0
- package/dist/llm/membrane.d.ts.map +1 -0
- package/dist/llm/membrane.js +123 -0
- package/dist/llm/membrane.js.map +1 -0
- package/dist/llm/providers/index.d.ts +5 -1
- package/dist/llm/providers/index.d.ts.map +1 -1
- package/dist/llm/providers/index.js +8 -1
- package/dist/llm/providers/index.js.map +1 -1
- package/dist/llm/redact.d.ts +39 -0
- package/dist/llm/redact.d.ts.map +1 -0
- package/dist/llm/redact.js +155 -0
- package/dist/llm/redact.js.map +1 -0
- package/dist/llm/sensitive-registry.d.ts +33 -0
- package/dist/llm/sensitive-registry.d.ts.map +1 -0
- package/dist/llm/sensitive-registry.js +106 -0
- package/dist/llm/sensitive-registry.js.map +1 -0
- package/dist/mcp-server.d.ts +11 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +520 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mdns.d.ts +17 -0
- package/dist/mdns.d.ts.map +1 -0
- package/dist/mdns.js +110 -0
- package/dist/mdns.js.map +1 -0
- package/dist/nerve/push.d.ts +26 -0
- package/dist/nerve/push.d.ts.map +1 -0
- package/dist/nerve/push.js +170 -0
- package/dist/nerve/push.js.map +1 -0
- package/dist/nerve/state.d.ts +35 -0
- package/dist/nerve/state.d.ts.map +1 -0
- package/dist/nerve/state.js +257 -0
- package/dist/nerve/state.js.map +1 -0
- package/dist/posture/engine.d.ts +41 -0
- package/dist/posture/engine.d.ts.map +1 -0
- package/dist/posture/engine.js +217 -0
- package/dist/posture/engine.js.map +1 -0
- package/dist/posture/index.d.ts +11 -0
- package/dist/posture/index.d.ts.map +1 -0
- package/dist/posture/index.js +10 -0
- package/dist/posture/index.js.map +1 -0
- package/dist/posture/middleware.d.ts +30 -0
- package/dist/posture/middleware.d.ts.map +1 -0
- package/dist/posture/middleware.js +92 -0
- package/dist/posture/middleware.js.map +1 -0
- package/dist/posture/types.d.ts +61 -0
- package/dist/posture/types.d.ts.map +1 -0
- package/dist/posture/types.js +48 -0
- package/dist/posture/types.js.map +1 -0
- package/dist/resend/inbox.d.ts +23 -0
- package/dist/resend/inbox.d.ts.map +1 -0
- package/dist/resend/inbox.js +198 -0
- package/dist/resend/inbox.js.map +1 -0
- package/dist/resend/webhooks.d.ts +30 -0
- package/dist/resend/webhooks.d.ts.map +1 -0
- package/dist/resend/webhooks.js +244 -0
- package/dist/resend/webhooks.js.map +1 -0
- package/dist/server.d.ts +5 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +773 -58
- package/dist/server.js.map +1 -1
- package/dist/settings.d.ts +14 -1
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +32 -1
- package/dist/settings.js.map +1 -1
- package/dist/tier/bond.d.ts +51 -0
- package/dist/tier/bond.d.ts.map +1 -0
- package/dist/tier/bond.js +154 -0
- package/dist/tier/bond.js.map +1 -0
- package/dist/tier/freeze.d.ts +21 -0
- package/dist/tier/freeze.d.ts.map +1 -0
- package/dist/tier/freeze.js +73 -0
- package/dist/tier/freeze.js.map +1 -0
- package/dist/tier/gate.d.ts +11 -0
- package/dist/tier/gate.d.ts.map +1 -0
- package/dist/tier/gate.js +25 -0
- package/dist/tier/gate.js.map +1 -0
- package/dist/tier/heartbeat.d.ts +22 -0
- package/dist/tier/heartbeat.d.ts.map +1 -0
- package/dist/tier/heartbeat.js +128 -0
- package/dist/tier/heartbeat.js.map +1 -0
- package/dist/tier/token.d.ts +22 -0
- package/dist/tier/token.d.ts.map +1 -0
- package/dist/tier/token.js +100 -0
- package/dist/tier/token.js.map +1 -0
- package/dist/tier/types.d.ts +44 -0
- package/dist/tier/types.d.ts.map +1 -0
- package/dist/tier/types.js +61 -0
- package/dist/tier/types.js.map +1 -0
- package/dist/updater.d.ts +32 -0
- package/dist/updater.d.ts.map +1 -0
- package/dist/updater.js +145 -0
- package/dist/updater.js.map +1 -0
- package/dist/vault/policy.d.ts +42 -0
- package/dist/vault/policy.d.ts.map +1 -0
- package/dist/vault/policy.js +159 -0
- package/dist/vault/policy.js.map +1 -0
- package/dist/vault/store.d.ts +6 -0
- package/dist/vault/store.d.ts.map +1 -1
- package/dist/vault/store.js +15 -5
- package/dist/vault/store.js.map +1 -1
- package/dist/vault/transfer.d.ts +33 -0
- package/dist/vault/transfer.d.ts.map +1 -0
- package/dist/vault/transfer.js +187 -0
- package/dist/vault/transfer.js.map +1 -0
- package/dist/voucher.d.ts +39 -0
- package/dist/voucher.d.ts.map +1 -0
- package/dist/voucher.js +105 -0
- package/dist/voucher.js.map +1 -0
- package/dist/webhooks/handlers.d.ts +10 -0
- package/dist/webhooks/handlers.d.ts.map +1 -1
- package/dist/webhooks/handlers.js +53 -0
- package/dist/webhooks/handlers.js.map +1 -1
- package/dist/webhooks/index.d.ts +2 -2
- package/dist/webhooks/index.d.ts.map +1 -1
- package/dist/webhooks/index.js +2 -2
- package/dist/webhooks/index.js.map +1 -1
- package/dist/webhooks/verify.d.ts +8 -0
- package/dist/webhooks/verify.d.ts.map +1 -1
- package/dist/webhooks/verify.js +56 -0
- package/dist/webhooks/verify.js.map +1 -1
- package/package.json +8 -2
- package/public/board.html +8 -3
- package/public/browser.html +8 -3
- package/public/library.html +8 -3
- package/public/observatory.html +8 -3
- package/public/ops.html +8 -3
- package/public/registry.html +627 -0
- package/public/roadmap.html +975 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resend inbound email inbox — pull-on-activity pattern.
|
|
3
|
+
*
|
|
4
|
+
* Instead of a timer, Core checks for pending emails whenever it's
|
|
5
|
+
* already doing work. The check is debounced: at most once every 2 minutes.
|
|
6
|
+
* Emails are pulled from the Cloudflare Worker's KV-backed inbox,
|
|
7
|
+
* processed through the Brain pipeline, and acknowledged.
|
|
8
|
+
*
|
|
9
|
+
* Call `checkResendInbox()` from any activity hook — it's cheap when
|
|
10
|
+
* there's nothing to do (single GET, empty array).
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { logActivity } from "../activity/log.js";
|
|
15
|
+
import { createLogger } from "../utils/logger.js";
|
|
16
|
+
import { processInboundEmail, sendResendReply } from "./webhooks.js";
|
|
17
|
+
const log = createLogger("resend.inbox");
|
|
18
|
+
/** Minimum interval between inbox checks (ms). */
|
|
19
|
+
const CHECK_DEBOUNCE_MS = 2 * 60 * 1000; // 2 minutes
|
|
20
|
+
/** Last time we checked the inbox. */
|
|
21
|
+
let lastCheckAt = 0;
|
|
22
|
+
/** Whether a check is currently in flight (prevents overlapping). */
|
|
23
|
+
let checking = false;
|
|
24
|
+
/** Resolved worker URL (cached after first call). */
|
|
25
|
+
let workerUrl = null;
|
|
26
|
+
let agentRegistryCache = null;
|
|
27
|
+
async function loadAgentRegistry() {
|
|
28
|
+
if (agentRegistryCache)
|
|
29
|
+
return agentRegistryCache;
|
|
30
|
+
try {
|
|
31
|
+
const raw = await readFile(join(process.cwd(), "brain", "identity", "email-agents.json"), "utf-8");
|
|
32
|
+
agentRegistryCache = JSON.parse(raw);
|
|
33
|
+
return agentRegistryCache;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Fallback — single default agent
|
|
37
|
+
return {
|
|
38
|
+
agents: { agent: { address: "agent@pqrsystems.com", label: "Core" } },
|
|
39
|
+
catchAll: "agent",
|
|
40
|
+
humanNotifyEmail: null,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function resolveAgent(registry, toAddresses) {
|
|
45
|
+
for (const addr of toAddresses) {
|
|
46
|
+
const local = addr.toLowerCase().split("@")[0];
|
|
47
|
+
if (registry.agents[local])
|
|
48
|
+
return registry.agents[local];
|
|
49
|
+
}
|
|
50
|
+
// Catch-all
|
|
51
|
+
return registry.agents[registry.catchAll] ?? { address: "agent@pqrsystems.com", label: "Core" };
|
|
52
|
+
}
|
|
53
|
+
function getWorkerUrl() {
|
|
54
|
+
if (workerUrl !== null)
|
|
55
|
+
return workerUrl;
|
|
56
|
+
const url = process.env.RESEND_WORKER_URL;
|
|
57
|
+
if (!url)
|
|
58
|
+
return null;
|
|
59
|
+
workerUrl = url.replace(/\/$/, "");
|
|
60
|
+
return workerUrl;
|
|
61
|
+
}
|
|
62
|
+
function getRelaySecret() {
|
|
63
|
+
return process.env.RELAY_SECRET || null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check the Resend Worker inbox for pending emails.
|
|
67
|
+
* Debounced — returns immediately if checked recently.
|
|
68
|
+
* Safe to call frequently from any activity path.
|
|
69
|
+
*/
|
|
70
|
+
export async function checkResendInbox() {
|
|
71
|
+
// Debounce
|
|
72
|
+
const now = Date.now();
|
|
73
|
+
if (now - lastCheckAt < CHECK_DEBOUNCE_MS)
|
|
74
|
+
return;
|
|
75
|
+
if (checking)
|
|
76
|
+
return;
|
|
77
|
+
const url = getWorkerUrl();
|
|
78
|
+
const secret = getRelaySecret();
|
|
79
|
+
if (!url || !secret)
|
|
80
|
+
return; // Not configured — silently skip
|
|
81
|
+
checking = true;
|
|
82
|
+
lastCheckAt = now;
|
|
83
|
+
try {
|
|
84
|
+
// Pull pending emails
|
|
85
|
+
const res = await fetch(`${url}/api/resend/inbox`, {
|
|
86
|
+
headers: { Authorization: `Bearer ${secret}` },
|
|
87
|
+
signal: AbortSignal.timeout(10_000),
|
|
88
|
+
});
|
|
89
|
+
if (!res.ok) {
|
|
90
|
+
log.warn("Inbox check failed", { status: res.status });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const data = (await res.json());
|
|
94
|
+
if (data.count === 0)
|
|
95
|
+
return;
|
|
96
|
+
log.info(`${data.count} pending email(s) in inbox`);
|
|
97
|
+
// Process each email
|
|
98
|
+
for (const email of data.emails) {
|
|
99
|
+
try {
|
|
100
|
+
await processEmail(email, url, secret);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
log.error("Failed to process inbox email", {
|
|
104
|
+
id: email.id,
|
|
105
|
+
from: email.from,
|
|
106
|
+
error: String(err),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
// Network error, Worker down, etc. — not critical, try next time
|
|
113
|
+
log.debug("Inbox check error", { error: String(err) });
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
checking = false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function processEmail(email, workerUrl, secret) {
|
|
120
|
+
if (!email.body?.trim()) {
|
|
121
|
+
// Empty email — just ack it
|
|
122
|
+
await ackEmail(email.id, workerUrl, secret);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Resolve which agent identity should handle this email
|
|
126
|
+
const registry = await loadAgentRegistry();
|
|
127
|
+
const agent = resolveAgent(registry, email.to);
|
|
128
|
+
logActivity({
|
|
129
|
+
source: "resend",
|
|
130
|
+
summary: `Processing inbound email from ${email.from} → ${agent.label}: "${email.subject}"`,
|
|
131
|
+
});
|
|
132
|
+
const reply = await processInboundEmail({
|
|
133
|
+
from: email.from,
|
|
134
|
+
subject: email.subject,
|
|
135
|
+
body: email.body,
|
|
136
|
+
date: email.created_at || email.received_at,
|
|
137
|
+
agentName: agent.label,
|
|
138
|
+
});
|
|
139
|
+
if (reply) {
|
|
140
|
+
const sent = await sendResendReply({
|
|
141
|
+
to: email.from,
|
|
142
|
+
subject: email.subject,
|
|
143
|
+
body: reply,
|
|
144
|
+
inReplyTo: email.message_id,
|
|
145
|
+
from: `${agent.label} <${agent.address}>`,
|
|
146
|
+
});
|
|
147
|
+
logActivity({
|
|
148
|
+
source: "resend",
|
|
149
|
+
summary: sent
|
|
150
|
+
? `${agent.label} replied to ${email.from}: "${email.subject}" (${reply.length} chars)`
|
|
151
|
+
: `${agent.label} failed to reply to ${email.from}: "${email.subject}"`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// Acknowledge — remove from Worker KV regardless of reply success
|
|
155
|
+
await ackEmail(email.id, workerUrl, secret);
|
|
156
|
+
}
|
|
157
|
+
async function ackEmail(id, workerUrl, secret) {
|
|
158
|
+
try {
|
|
159
|
+
await fetch(`${workerUrl}/api/resend/inbox/${id}`, {
|
|
160
|
+
method: "DELETE",
|
|
161
|
+
headers: { Authorization: `Bearer ${secret}` },
|
|
162
|
+
signal: AbortSignal.timeout(5_000),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
log.warn("Failed to ack email", { id, error: String(err) });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Force an immediate inbox check, bypassing the debounce.
|
|
171
|
+
* Useful for manual triggers (e.g., "check email" command).
|
|
172
|
+
*/
|
|
173
|
+
export async function forceCheckResendInbox() {
|
|
174
|
+
lastCheckAt = 0;
|
|
175
|
+
checking = false;
|
|
176
|
+
const url = getWorkerUrl();
|
|
177
|
+
const secret = getRelaySecret();
|
|
178
|
+
if (!url || !secret)
|
|
179
|
+
return 0;
|
|
180
|
+
// Quick count check before full processing
|
|
181
|
+
try {
|
|
182
|
+
const res = await fetch(`${url}/api/resend/inbox`, {
|
|
183
|
+
headers: { Authorization: `Bearer ${secret}` },
|
|
184
|
+
signal: AbortSignal.timeout(10_000),
|
|
185
|
+
});
|
|
186
|
+
if (!res.ok)
|
|
187
|
+
return 0;
|
|
188
|
+
const data = (await res.json());
|
|
189
|
+
if (data.count === 0)
|
|
190
|
+
return 0;
|
|
191
|
+
await checkResendInbox();
|
|
192
|
+
return data.count;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/resend/inbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resend inbound email webhook provider.
|
|
3
|
+
*
|
|
4
|
+
* Handles email.received events from Resend via Svix-signed webhooks.
|
|
5
|
+
* Fetches full email body from Resend API, processes through the email Brain
|
|
6
|
+
* pipeline, and replies via Resend API with proper threading headers.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Send a reply via Resend API with proper threading headers.
|
|
10
|
+
*/
|
|
11
|
+
export declare function sendResendReply(opts: {
|
|
12
|
+
to: string;
|
|
13
|
+
subject: string;
|
|
14
|
+
body: string;
|
|
15
|
+
inReplyTo?: string;
|
|
16
|
+
from?: string;
|
|
17
|
+
}): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* Process an inbound email through the Brain + LLM + capability pipeline.
|
|
20
|
+
* Reuses the same logic as the Gmail email handler in server.ts.
|
|
21
|
+
*/
|
|
22
|
+
export declare function processInboundEmail(opts: {
|
|
23
|
+
from: string;
|
|
24
|
+
subject: string;
|
|
25
|
+
body: string;
|
|
26
|
+
date: string;
|
|
27
|
+
agentName?: string;
|
|
28
|
+
}): Promise<string | null>;
|
|
29
|
+
export declare const resendProvider: import("../webhooks/types.js").WebhookProvider;
|
|
30
|
+
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/resend/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuFH;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,OAAO,CAAC,CAmDnB;AAID;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuFzB;AAID,eAAO,MAAM,cAAc,gDAqEzB,CAAC"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resend inbound email webhook provider.
|
|
3
|
+
*
|
|
4
|
+
* Handles email.received events from Resend via Svix-signed webhooks.
|
|
5
|
+
* Fetches full email body from Resend API, processes through the email Brain
|
|
6
|
+
* pipeline, and replies via Resend API with proper threading headers.
|
|
7
|
+
*/
|
|
8
|
+
import { createSvixStyleProvider, safeHandler } from "../webhooks/handlers.js";
|
|
9
|
+
import { logActivity } from "../activity/log.js";
|
|
10
|
+
import { createLogger } from "../utils/logger.js";
|
|
11
|
+
import { Brain } from "../brain.js";
|
|
12
|
+
import { FileSystemLongTermMemory } from "../memory/file-backed.js";
|
|
13
|
+
import { getInstanceName } from "../instance.js";
|
|
14
|
+
import { getProvider as getLLMProvider } from "../llm/providers/index.js";
|
|
15
|
+
import { resolveProvider, resolveChatModel } from "../settings.js";
|
|
16
|
+
import { readHuman } from "../auth/identity.js";
|
|
17
|
+
import { getCapabilityRegistry } from "../capabilities/index.js";
|
|
18
|
+
const log = createLogger("resend.webhooks");
|
|
19
|
+
const RESEND_API = "https://api.resend.com";
|
|
20
|
+
const MEMORY_DIR = "brain/memory";
|
|
21
|
+
// ── Resend API helpers ──────────────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Fetch the full email content from Resend's receiving API.
|
|
24
|
+
* The webhook only includes metadata — the body must be fetched separately.
|
|
25
|
+
*/
|
|
26
|
+
async function fetchEmailContent(emailId) {
|
|
27
|
+
const apiKey = process.env.RESEND_API_KEY;
|
|
28
|
+
if (!apiKey) {
|
|
29
|
+
log.error("RESEND_API_KEY not set — cannot fetch email content");
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(`${RESEND_API}/emails/receiving/${emailId}`, {
|
|
34
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
35
|
+
signal: AbortSignal.timeout(15_000),
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
log.error("Resend API error fetching email", {
|
|
39
|
+
emailId,
|
|
40
|
+
status: res.status,
|
|
41
|
+
statusText: res.statusText,
|
|
42
|
+
});
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return (await res.json());
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
log.error("Failed to fetch email from Resend", {
|
|
49
|
+
emailId,
|
|
50
|
+
error: String(err),
|
|
51
|
+
});
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Send a reply via Resend API with proper threading headers.
|
|
57
|
+
*/
|
|
58
|
+
export async function sendResendReply(opts) {
|
|
59
|
+
const apiKey = process.env.RESEND_API_KEY;
|
|
60
|
+
if (!apiKey) {
|
|
61
|
+
log.error("RESEND_API_KEY not set — cannot send reply");
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const from = opts.from ?? `${getInstanceName()} <agent@pqrsystems.com>`;
|
|
65
|
+
const payload = {
|
|
66
|
+
from,
|
|
67
|
+
to: [opts.to],
|
|
68
|
+
subject: opts.subject.startsWith("Re:") ? opts.subject : `Re: ${opts.subject}`,
|
|
69
|
+
text: opts.body,
|
|
70
|
+
};
|
|
71
|
+
// Threading headers
|
|
72
|
+
if (opts.inReplyTo) {
|
|
73
|
+
payload.headers = {
|
|
74
|
+
"In-Reply-To": opts.inReplyTo,
|
|
75
|
+
References: opts.inReplyTo,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const res = await fetch(`${RESEND_API}/emails`, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: {
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
Authorization: `Bearer ${apiKey}`,
|
|
84
|
+
},
|
|
85
|
+
body: JSON.stringify(payload),
|
|
86
|
+
signal: AbortSignal.timeout(15_000),
|
|
87
|
+
});
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
const text = await res.text().catch(() => "");
|
|
90
|
+
log.error("Resend send failed", {
|
|
91
|
+
status: res.status,
|
|
92
|
+
to: opts.to,
|
|
93
|
+
error: text,
|
|
94
|
+
});
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
log.info("Resend reply sent", { to: opts.to, subject: opts.subject });
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
log.error("Resend send exception", { to: opts.to, error: String(err) });
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ── Email processing (shared Brain pipeline) ────────────────────────────────
|
|
106
|
+
/**
|
|
107
|
+
* Process an inbound email through the Brain + LLM + capability pipeline.
|
|
108
|
+
* Reuses the same logic as the Gmail email handler in server.ts.
|
|
109
|
+
*/
|
|
110
|
+
export async function processInboundEmail(opts) {
|
|
111
|
+
const human = await readHuman();
|
|
112
|
+
const name = human?.name ?? "Human";
|
|
113
|
+
const agentLabel = opts.agentName ?? getInstanceName();
|
|
114
|
+
if (!opts.body.trim())
|
|
115
|
+
return null;
|
|
116
|
+
// Build a lightweight Brain for email context
|
|
117
|
+
const ltm = new FileSystemLongTermMemory(MEMORY_DIR);
|
|
118
|
+
await ltm.init();
|
|
119
|
+
const emailBrain = new Brain({
|
|
120
|
+
systemPrompt: [
|
|
121
|
+
`You are ${agentLabel}, a personal AI agent paired with ${name}. You run locally on ${name}'s machine.`,
|
|
122
|
+
`You are responding to an email that was sent to you at ${agentLabel.toLowerCase()}@pqrsystems.com. This is a working email channel — you received this email and your reply will be sent back automatically.`,
|
|
123
|
+
``,
|
|
124
|
+
`Your capabilities — USE THEM when the email requests action:`,
|
|
125
|
+
`- Google Calendar: CREATE, UPDATE, DELETE events using [CALENDAR_ACTION] blocks.`,
|
|
126
|
+
`- Gmail: SEND emails and REPLY to threads using [EMAIL_ACTION] blocks.`,
|
|
127
|
+
`- Google Docs & Sheets: CREATE documents using [DOC_ACTION] blocks.`,
|
|
128
|
+
`- Task board for tracking work.`,
|
|
129
|
+
`- Long-term memory of past conversations and learned facts.`,
|
|
130
|
+
``,
|
|
131
|
+
...(getCapabilityRegistry()?.getPromptInstructions({ origin: "email", name }) ?? "").split("\n"),
|
|
132
|
+
``,
|
|
133
|
+
`Rules for email replies:`,
|
|
134
|
+
`- Write a natural, helpful reply as plain text (no markdown).`,
|
|
135
|
+
`- Be warm and direct — you have personality, you're not a corporate assistant.`,
|
|
136
|
+
`- Keep it concise and appropriate for email.`,
|
|
137
|
+
`- Do not include a subject line. Just write the body of the reply.`,
|
|
138
|
+
`- NEVER claim you can't do something you clearly just did (you ARE sending this email).`,
|
|
139
|
+
`- When someone asks you to DO something (schedule, create, send), DO IT with the appropriate action block — don't just acknowledge it.`,
|
|
140
|
+
`- Action blocks will be stripped from the email reply automatically. The recipient only sees your text.`,
|
|
141
|
+
`- Sign off as "— ${agentLabel}"`,
|
|
142
|
+
].join("\n"),
|
|
143
|
+
}, ltm);
|
|
144
|
+
const ctx = await emailBrain.getContextForTurn({
|
|
145
|
+
userInput: opts.body,
|
|
146
|
+
conversationHistory: [],
|
|
147
|
+
});
|
|
148
|
+
// Inject email metadata so the agent knows the context
|
|
149
|
+
ctx.messages.splice(1, 0, {
|
|
150
|
+
role: "system",
|
|
151
|
+
content: [
|
|
152
|
+
`--- Incoming email ---`,
|
|
153
|
+
`From: ${opts.from}`,
|
|
154
|
+
`Subject: ${opts.subject}`,
|
|
155
|
+
`Date: ${opts.date}`,
|
|
156
|
+
`--- End email metadata ---`,
|
|
157
|
+
].join("\n"),
|
|
158
|
+
});
|
|
159
|
+
// Add the email body as the "user" message
|
|
160
|
+
ctx.messages.push({ role: "user", content: opts.body });
|
|
161
|
+
const provider = getLLMProvider(resolveProvider());
|
|
162
|
+
const model = resolveChatModel();
|
|
163
|
+
let reply = await provider.completeChat(ctx.messages, model ?? undefined);
|
|
164
|
+
if (!reply?.trim())
|
|
165
|
+
return null;
|
|
166
|
+
// Process action blocks from the AI response via capability registry
|
|
167
|
+
const capReg = getCapabilityRegistry();
|
|
168
|
+
if (capReg) {
|
|
169
|
+
const { cleaned } = await capReg.processResponse(reply, { origin: "email", name });
|
|
170
|
+
reply = cleaned;
|
|
171
|
+
}
|
|
172
|
+
// Guard: if stripping action blocks left only a signature, don't send
|
|
173
|
+
const signaturePattern = new RegExp(`[\\s\\n]*[—\\-]+\\s*${getInstanceName()}[\\s.!]*$`, "i");
|
|
174
|
+
const withoutSignature = reply.replace(signaturePattern, "").trim();
|
|
175
|
+
if (!withoutSignature) {
|
|
176
|
+
log.warn("Email reply was empty after stripping action blocks — not sending", {
|
|
177
|
+
from: opts.from,
|
|
178
|
+
subject: opts.subject,
|
|
179
|
+
});
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
return reply.trim();
|
|
183
|
+
}
|
|
184
|
+
// ── Webhook provider ─────────────────────────────────────────────────────────
|
|
185
|
+
export const resendProvider = createSvixStyleProvider({
|
|
186
|
+
name: "resend",
|
|
187
|
+
process: safeHandler("resend", async (payload) => {
|
|
188
|
+
const event = payload;
|
|
189
|
+
if (event?.type !== "email.received") {
|
|
190
|
+
return {
|
|
191
|
+
handled: false,
|
|
192
|
+
message: `Unhandled event type: ${event?.type ?? "unknown"}`,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const { email_id, from, subject, message_id, created_at } = event.data;
|
|
196
|
+
log.info("Resend inbound email received", { email_id, from, subject });
|
|
197
|
+
logActivity({
|
|
198
|
+
source: "resend",
|
|
199
|
+
summary: `Inbound email from ${from}: "${subject}"`,
|
|
200
|
+
});
|
|
201
|
+
// Fetch full email content (webhook only has metadata)
|
|
202
|
+
const content = await fetchEmailContent(email_id);
|
|
203
|
+
if (!content) {
|
|
204
|
+
return {
|
|
205
|
+
handled: false,
|
|
206
|
+
message: `Failed to fetch email content for ${email_id}`,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const body = content.text || content.html?.replace(/<[^>]+>/g, " ") || "";
|
|
210
|
+
if (!body.trim()) {
|
|
211
|
+
return { handled: true, message: "Empty email body — skipped" };
|
|
212
|
+
}
|
|
213
|
+
// Process through Brain pipeline
|
|
214
|
+
const reply = await processInboundEmail({
|
|
215
|
+
from,
|
|
216
|
+
subject,
|
|
217
|
+
body,
|
|
218
|
+
date: created_at || new Date().toISOString(),
|
|
219
|
+
});
|
|
220
|
+
if (!reply) {
|
|
221
|
+
return { handled: true, message: "No reply generated — skipped" };
|
|
222
|
+
}
|
|
223
|
+
// Send reply via Resend with threading
|
|
224
|
+
const sent = await sendResendReply({
|
|
225
|
+
to: from,
|
|
226
|
+
subject,
|
|
227
|
+
body: reply,
|
|
228
|
+
inReplyTo: message_id,
|
|
229
|
+
});
|
|
230
|
+
logActivity({
|
|
231
|
+
source: "resend",
|
|
232
|
+
summary: sent
|
|
233
|
+
? `Replied to ${from}: "${subject}" (${reply.length} chars)`
|
|
234
|
+
: `Failed to reply to ${from}: "${subject}"`,
|
|
235
|
+
});
|
|
236
|
+
return {
|
|
237
|
+
handled: true,
|
|
238
|
+
message: sent
|
|
239
|
+
? `Processed and replied to email from ${from}`
|
|
240
|
+
: `Processed email from ${from} but reply send failed`,
|
|
241
|
+
};
|
|
242
|
+
}),
|
|
243
|
+
});
|
|
244
|
+
//# sourceMappingURL=webhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/resend/webhooks.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* Hono app: serves static UI, handles pairing/auth, streams chat via Ollama (local) or OpenRouter (cloud).
|
|
4
4
|
*/
|
|
5
5
|
export declare function getStartupToken(): string | null;
|
|
6
|
-
declare function start(
|
|
6
|
+
declare function start(opts?: {
|
|
7
|
+
tier?: import("./tier/types.js").TierName;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
/** Returns the port the server is actually listening on (resolves port 0). */
|
|
10
|
+
export declare function getActualPort(): number;
|
|
7
11
|
export { start };
|
|
8
12
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuTH,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/C;AA2gKD,iBAAe,KAAK,CAAC,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,iBAAiB,EAAE,QAAQ,CAAA;CAAE,iBAghBxE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
|