@agenticmail/core 0.9.9 → 0.9.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/index.cjs +76 -2
- package/dist/index.d.cts +58 -5
- package/dist/index.d.ts +58 -5
- package/dist/index.js +70 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -713,6 +713,7 @@ __export(index_exports, {
|
|
|
713
713
|
AgentDeletionService: () => AgentDeletionService,
|
|
714
714
|
AgentMemoryStore: () => AgentMemoryStore,
|
|
715
715
|
AgenticMailClient: () => AgenticMailClient,
|
|
716
|
+
BRIDGE_OPERATOR_LIVE_WINDOW_MS: () => BRIDGE_OPERATOR_LIVE_WINDOW_MS,
|
|
716
717
|
CloudflareClient: () => CloudflareClient,
|
|
717
718
|
DEFAULT_AGENT_NAME: () => DEFAULT_AGENT_NAME,
|
|
718
719
|
DEFAULT_AGENT_ROLE: () => DEFAULT_AGENT_ROLE,
|
|
@@ -743,10 +744,14 @@ __export(index_exports, {
|
|
|
743
744
|
UnsafeApiUrlError: () => UnsafeApiUrlError,
|
|
744
745
|
WARNING_THRESHOLD: () => WARNING_THRESHOLD,
|
|
745
746
|
assertWithinBase: () => assertWithinBase,
|
|
747
|
+
bridgeWakeErrorMessage: () => bridgeWakeErrorMessage,
|
|
748
|
+
bridgeWakeLastSeenAgeMs: () => bridgeWakeLastSeenAgeMs,
|
|
746
749
|
buildApiUrl: () => buildApiUrl,
|
|
747
750
|
buildInboundSecurityAdvisory: () => buildInboundSecurityAdvisory,
|
|
748
751
|
classifyEmailRoute: () => classifyEmailRoute,
|
|
752
|
+
classifyResumeError: () => classifyResumeError,
|
|
749
753
|
closeDatabase: () => closeDatabase,
|
|
754
|
+
composeBridgeWakePrompt: () => composeBridgeWakePrompt,
|
|
750
755
|
createTestDatabase: () => createTestDatabase,
|
|
751
756
|
debug: () => debug,
|
|
752
757
|
debugWarn: () => debugWarn,
|
|
@@ -782,6 +787,7 @@ __export(index_exports, {
|
|
|
782
787
|
scoreEmail: () => scoreEmail,
|
|
783
788
|
setOperatorEmail: () => setOperatorEmail,
|
|
784
789
|
setTelemetryVersion: () => setTelemetryVersion,
|
|
790
|
+
shouldSkipBridgeWakeForLiveOperator: () => shouldSkipBridgeWakeForLiveOperator,
|
|
785
791
|
startRelayBridge: () => startRelayBridge,
|
|
786
792
|
threadIdFor: () => threadIdFor,
|
|
787
793
|
tryJoin: () => tryJoin,
|
|
@@ -805,8 +811,7 @@ var MailSender = class {
|
|
|
805
811
|
pass: options.password
|
|
806
812
|
},
|
|
807
813
|
tls: {
|
|
808
|
-
rejectUnauthorized:
|
|
809
|
-
// Local dev — no TLS
|
|
814
|
+
rejectUnauthorized: options.tlsRejectUnauthorized ?? true
|
|
810
815
|
},
|
|
811
816
|
connectionTimeout: 1e4,
|
|
812
817
|
// 10s to establish TCP connection
|
|
@@ -7233,6 +7238,69 @@ function hostSessionStoragePath() {
|
|
|
7233
7238
|
return storagePath();
|
|
7234
7239
|
}
|
|
7235
7240
|
|
|
7241
|
+
// src/host-bridge.ts
|
|
7242
|
+
var BRIDGE_OPERATOR_LIVE_WINDOW_MS = 3e4;
|
|
7243
|
+
var DEFAULT_EXPIRED_MARKERS = [
|
|
7244
|
+
"session not found",
|
|
7245
|
+
"invalid session",
|
|
7246
|
+
"session expired",
|
|
7247
|
+
"no such session",
|
|
7248
|
+
"unknown session",
|
|
7249
|
+
"thread not found",
|
|
7250
|
+
"invalid thread",
|
|
7251
|
+
"thread expired",
|
|
7252
|
+
"no such thread",
|
|
7253
|
+
"unknown thread"
|
|
7254
|
+
];
|
|
7255
|
+
var DEFAULT_SDK_MISSING_MARKERS = [
|
|
7256
|
+
"cannot find module",
|
|
7257
|
+
"could not be found",
|
|
7258
|
+
"command not found"
|
|
7259
|
+
];
|
|
7260
|
+
function bridgeWakeErrorMessage(err) {
|
|
7261
|
+
return err?.message ?? String(err);
|
|
7262
|
+
}
|
|
7263
|
+
function classifyResumeError(err, options = {}) {
|
|
7264
|
+
const msg = bridgeWakeErrorMessage(err).toLowerCase();
|
|
7265
|
+
const expiredMarkers = options.expiredMarkers ?? DEFAULT_EXPIRED_MARKERS;
|
|
7266
|
+
const sdkMissingMarkers = options.sdkMissingMarkers ?? DEFAULT_SDK_MISSING_MARKERS;
|
|
7267
|
+
if (expiredMarkers.some((marker) => msg.includes(marker))) return "session-expired";
|
|
7268
|
+
if (sdkMissingMarkers.some((marker) => msg.includes(marker))) return "sdk-missing";
|
|
7269
|
+
return "other";
|
|
7270
|
+
}
|
|
7271
|
+
function bridgeWakeLastSeenAgeMs(session, nowMs = Date.now()) {
|
|
7272
|
+
if (!session) return null;
|
|
7273
|
+
return nowMs - session.lastSeenMs;
|
|
7274
|
+
}
|
|
7275
|
+
function shouldSkipBridgeWakeForLiveOperator(session, nowMs = Date.now(), liveWindowMs = BRIDGE_OPERATOR_LIVE_WINDOW_MS) {
|
|
7276
|
+
const ageMs = bridgeWakeLastSeenAgeMs(session, nowMs);
|
|
7277
|
+
return ageMs !== null && ageMs < liveWindowMs;
|
|
7278
|
+
}
|
|
7279
|
+
function composeBridgeWakePrompt(args) {
|
|
7280
|
+
const subject = args.subject ?? "(no subject)";
|
|
7281
|
+
const from = args.from ?? "unknown";
|
|
7282
|
+
const preview = (args.preview ?? "").slice(0, 600);
|
|
7283
|
+
return [
|
|
7284
|
+
`\u{1F380} Bridge mail arrived \u2014 headless wake.`,
|
|
7285
|
+
"",
|
|
7286
|
+
`You are being resumed against your last session because new mail landed in your bridge inbox (${args.bridgeName}@localhost) and you weren't actively at the keyboard.`,
|
|
7287
|
+
"",
|
|
7288
|
+
`Trigger:`,
|
|
7289
|
+
` UID: ${args.uid}`,
|
|
7290
|
+
` From: ${from}`,
|
|
7291
|
+
` Subject: ${subject}`,
|
|
7292
|
+
` Preview: ${preview}`,
|
|
7293
|
+
"",
|
|
7294
|
+
`Read it with mcp__agenticmail__read_email({ uid: ${args.uid} }) and decide:`,
|
|
7295
|
+
` \xB7 Does it need a reply from YOU (the operator's session)? Reply via mcp__agenticmail__reply_email.`,
|
|
7296
|
+
` \xB7 Does it need a teammate to act? Forward / re-route by replying with wake: ["<teammate>"].`,
|
|
7297
|
+
` \xB7 Is it [NEEDS OPERATOR] / [BLOCKED]? Then it's actually for the human \u2014 mark it unread, and the operator will see it on their next keystroke.`,
|
|
7298
|
+
` \xB7 Is it FYI noise? mark_read and exit.`,
|
|
7299
|
+
"",
|
|
7300
|
+
`Keep this turn SHORT. You're being resumed to handle ONE piece of mail, not to continue the prior conversation.`
|
|
7301
|
+
].join("\n");
|
|
7302
|
+
}
|
|
7303
|
+
|
|
7236
7304
|
// src/util/safe-url.ts
|
|
7237
7305
|
var UnsafeApiUrlError = class extends Error {
|
|
7238
7306
|
constructor(raw, reason) {
|
|
@@ -8910,6 +8978,7 @@ function parse(raw) {
|
|
|
8910
8978
|
AgentDeletionService,
|
|
8911
8979
|
AgentMemoryStore,
|
|
8912
8980
|
AgenticMailClient,
|
|
8981
|
+
BRIDGE_OPERATOR_LIVE_WINDOW_MS,
|
|
8913
8982
|
CloudflareClient,
|
|
8914
8983
|
DEFAULT_AGENT_NAME,
|
|
8915
8984
|
DEFAULT_AGENT_ROLE,
|
|
@@ -8940,10 +9009,14 @@ function parse(raw) {
|
|
|
8940
9009
|
UnsafeApiUrlError,
|
|
8941
9010
|
WARNING_THRESHOLD,
|
|
8942
9011
|
assertWithinBase,
|
|
9012
|
+
bridgeWakeErrorMessage,
|
|
9013
|
+
bridgeWakeLastSeenAgeMs,
|
|
8943
9014
|
buildApiUrl,
|
|
8944
9015
|
buildInboundSecurityAdvisory,
|
|
8945
9016
|
classifyEmailRoute,
|
|
9017
|
+
classifyResumeError,
|
|
8946
9018
|
closeDatabase,
|
|
9019
|
+
composeBridgeWakePrompt,
|
|
8947
9020
|
createTestDatabase,
|
|
8948
9021
|
debug,
|
|
8949
9022
|
debugWarn,
|
|
@@ -8979,6 +9052,7 @@ function parse(raw) {
|
|
|
8979
9052
|
scoreEmail,
|
|
8980
9053
|
setOperatorEmail,
|
|
8981
9054
|
setTelemetryVersion,
|
|
9055
|
+
shouldSkipBridgeWakeForLiveOperator,
|
|
8982
9056
|
startRelayBridge,
|
|
8983
9057
|
threadIdFor,
|
|
8984
9058
|
tryJoin,
|
package/dist/index.d.cts
CHANGED
|
@@ -481,6 +481,7 @@ interface MailSenderOptions {
|
|
|
481
481
|
password: string;
|
|
482
482
|
authUser?: string;
|
|
483
483
|
secure?: boolean;
|
|
484
|
+
tlsRejectUnauthorized?: boolean;
|
|
484
485
|
}
|
|
485
486
|
interface SendResultWithRaw extends SendResult {
|
|
486
487
|
/** Raw RFC822 message bytes (for appending to Sent folder) */
|
|
@@ -1899,8 +1900,8 @@ declare function operatorPrefsStoragePath(): string;
|
|
|
1899
1900
|
*
|
|
1900
1901
|
* # What this is for
|
|
1901
1902
|
*
|
|
1902
|
-
* When a sub-agent replies into
|
|
1903
|
-
* (`claudecode@localhost` / `codex@localhost`), the dispatcher
|
|
1903
|
+
* When a sub-agent replies into a host bridge inbox
|
|
1904
|
+
* (`claudecode@localhost` / `codex@localhost` / etc.), the dispatcher
|
|
1904
1905
|
* historically had no way to react: bridges are skipped by
|
|
1905
1906
|
* `shouldWatch` because they belong to the human operator's host CLI,
|
|
1906
1907
|
* not to an automated worker. The mail would sit unread until the
|
|
@@ -1933,6 +1934,12 @@ declare function operatorPrefsStoragePath(): string;
|
|
|
1933
1934
|
* "sessionId": "019a2b3c-…",
|
|
1934
1935
|
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1935
1936
|
* "lastSeenMs": 1778905100000
|
|
1937
|
+
* },
|
|
1938
|
+
* "openclaw": {
|
|
1939
|
+
* "sessionId": "openclaw-session-key",
|
|
1940
|
+
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1941
|
+
* "lastSeenMs": 1778905000000,
|
|
1942
|
+
* "resumeMode": "wake"
|
|
1936
1943
|
* }
|
|
1937
1944
|
* }
|
|
1938
1945
|
* }
|
|
@@ -1963,14 +1970,24 @@ declare function operatorPrefsStoragePath(): string;
|
|
|
1963
1970
|
* that crashes the next reader. Same shape as `dispatcher-state.ts`.
|
|
1964
1971
|
*/
|
|
1965
1972
|
/** Canonical names for the host integrations that own bridge inboxes. */
|
|
1966
|
-
type HostName = 'claudecode' | 'codex';
|
|
1973
|
+
type HostName = 'claudecode' | 'codex' | 'openclaw' | 'gemini' | 'hermes';
|
|
1974
|
+
/**
|
|
1975
|
+
* How a host can be woken from a persisted session record.
|
|
1976
|
+
*
|
|
1977
|
+
* - `resume`: the host can resume a durable prior conversation/thread.
|
|
1978
|
+
* - `wake`: the host can target a live or recently known session key, but does
|
|
1979
|
+
* not guarantee full headless resume semantics.
|
|
1980
|
+
* - `wake-only`: the host can receive a wake notification, but the dispatcher
|
|
1981
|
+
* must not treat it as a resumed worker turn.
|
|
1982
|
+
*/
|
|
1983
|
+
type HostSessionResumeMode = 'resume' | 'wake' | 'wake-only';
|
|
1967
1984
|
/**
|
|
1968
1985
|
* A snapshot of one host CLI's last-known session. Persisted to disk
|
|
1969
1986
|
* by the mail-hook on every fire; loaded by the dispatcher when
|
|
1970
1987
|
* bridge mail arrives so a resume can be attempted.
|
|
1971
1988
|
*/
|
|
1972
1989
|
interface HostSession {
|
|
1973
|
-
/** Stable session_id from the host CLI
|
|
1990
|
+
/** Stable session_id/thread_id/session key from the host CLI/runtime. */
|
|
1974
1991
|
sessionId: string;
|
|
1975
1992
|
/** Wall-clock timestamp of the last hook fire on this session. */
|
|
1976
1993
|
lastSeenMs: number;
|
|
@@ -1980,6 +1997,10 @@ interface HostSession {
|
|
|
1980
1997
|
/** Optional: model name the host session was using, surfaced
|
|
1981
1998
|
* in logs for diagnostic context. */
|
|
1982
1999
|
model?: string;
|
|
2000
|
+
/** Optional: describes whether this host supports true resume or only wake. */
|
|
2001
|
+
resumeMode?: HostSessionResumeMode;
|
|
2002
|
+
/** Optional host-specific metadata. Must not contain secrets. */
|
|
2003
|
+
hostMetadata?: Record<string, unknown>;
|
|
1983
2004
|
}
|
|
1984
2005
|
/** Default freshness window — sessions older than this are skipped. */
|
|
1985
2006
|
declare const DEFAULT_SESSION_MAX_AGE_MS: number;
|
|
@@ -2017,6 +2038,38 @@ declare function forgetHostSession(host: HostName): void;
|
|
|
2017
2038
|
/** Exposed for tests + the `agenticmail status` diagnostic command. */
|
|
2018
2039
|
declare function hostSessionStoragePath(): string;
|
|
2019
2040
|
|
|
2041
|
+
type BridgeWakeError = 'session-expired' | 'sdk-missing' | 'timeout' | 'other';
|
|
2042
|
+
interface BridgeWakeResult {
|
|
2043
|
+
ok: boolean;
|
|
2044
|
+
text?: string;
|
|
2045
|
+
error?: BridgeWakeError;
|
|
2046
|
+
errorMessage?: string;
|
|
2047
|
+
durationMs?: number;
|
|
2048
|
+
}
|
|
2049
|
+
interface BridgeWakePromptArgs {
|
|
2050
|
+
bridgeName: string;
|
|
2051
|
+
uid: number;
|
|
2052
|
+
subject?: string;
|
|
2053
|
+
from?: string;
|
|
2054
|
+
preview?: string;
|
|
2055
|
+
}
|
|
2056
|
+
interface ResumeErrorClassificationOptions {
|
|
2057
|
+
expiredMarkers?: readonly string[];
|
|
2058
|
+
sdkMissingMarkers?: readonly string[];
|
|
2059
|
+
}
|
|
2060
|
+
declare const BRIDGE_OPERATOR_LIVE_WINDOW_MS = 30000;
|
|
2061
|
+
declare function bridgeWakeErrorMessage(err: unknown): string;
|
|
2062
|
+
declare function classifyResumeError(err: unknown, options?: ResumeErrorClassificationOptions): BridgeWakeError;
|
|
2063
|
+
declare function bridgeWakeLastSeenAgeMs(session: Pick<HostSession, 'lastSeenMs'> | null | undefined, nowMs?: number): number | null;
|
|
2064
|
+
declare function shouldSkipBridgeWakeForLiveOperator(session: Pick<HostSession, 'lastSeenMs'> | null | undefined, nowMs?: number, liveWindowMs?: number): boolean;
|
|
2065
|
+
/**
|
|
2066
|
+
* Build the prompt a host session sees on bridge wake. Host adapters
|
|
2067
|
+
* keep their own SDK resume call, but share this operator-facing
|
|
2068
|
+
* instruction shape so Claude Code, Codex, OpenClaw and later hosts
|
|
2069
|
+
* do not drift semantically.
|
|
2070
|
+
*/
|
|
2071
|
+
declare function composeBridgeWakePrompt(args: BridgeWakePromptArgs): string;
|
|
2072
|
+
|
|
2020
2073
|
/**
|
|
2021
2074
|
* SSRF-safe URL validation for the AgenticMail API base URL.
|
|
2022
2075
|
*
|
|
@@ -2624,4 +2677,4 @@ declare class AgentMemoryStore {
|
|
|
2624
2677
|
renderForPrompt(memory: AgentMemoryRead | null): string;
|
|
2625
2678
|
}
|
|
2626
2679
|
|
|
2627
|
-
export { AGENT_ROLES, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryFields, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, type CachedMessage, CloudflareClient, type CreateAgentOptions, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_SESSION_MAX_AGE_MS, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type HostName, type HostSession, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, type LinkAdvisory, type LocalSmtpConfig, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, type ParsedAttachment, type ParsedEmail, type ParsedSms, PathTraversalError, type PurchasedDomain, REDACTED, RELAY_PRESETS, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type TunnelConfig, TunnelManager, UnsafeApiUrlError, WARNING_THRESHOLD, type WatcherOptions, assertWithinBase, buildApiUrl, buildInboundSecurityAdvisory, classifyEmailRoute, closeDatabase, createTestDatabase, debug, debugWarn, ensureDataDir, extractVerificationCode, flushTelemetry, forgetHostSession, getDatabase, getOperatorEmail, getSmsProvider, hostSessionStoragePath, isInternalEmail, isSessionFresh, isValidPhoneNumber, loadHostSession, mapProviderSmsStatus, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, redactSmsConfig, resolveConfig, safeJoin, sanitizeEmail, saveConfig, saveHostSession, scanOutboundEmail, scoreEmail, setOperatorEmail, setTelemetryVersion, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|
|
2680
|
+
export { AGENT_ROLES, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryFields, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, BRIDGE_OPERATOR_LIVE_WINDOW_MS, type BridgeWakeError, type BridgeWakePromptArgs, type BridgeWakeResult, type CachedMessage, CloudflareClient, type CreateAgentOptions, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_SESSION_MAX_AGE_MS, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type HostName, type HostSession, type HostSessionResumeMode, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, type LinkAdvisory, type LocalSmtpConfig, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, type ParsedAttachment, type ParsedEmail, type ParsedSms, PathTraversalError, type PurchasedDomain, REDACTED, RELAY_PRESETS, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, type ResumeErrorClassificationOptions, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type TunnelConfig, TunnelManager, UnsafeApiUrlError, WARNING_THRESHOLD, type WatcherOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, buildInboundSecurityAdvisory, classifyEmailRoute, classifyResumeError, closeDatabase, composeBridgeWakePrompt, createTestDatabase, debug, debugWarn, ensureDataDir, extractVerificationCode, flushTelemetry, forgetHostSession, getDatabase, getOperatorEmail, getSmsProvider, hostSessionStoragePath, isInternalEmail, isSessionFresh, isValidPhoneNumber, loadHostSession, mapProviderSmsStatus, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, redactSmsConfig, resolveConfig, safeJoin, sanitizeEmail, saveConfig, saveHostSession, scanOutboundEmail, scoreEmail, setOperatorEmail, setTelemetryVersion, shouldSkipBridgeWakeForLiveOperator, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|
package/dist/index.d.ts
CHANGED
|
@@ -481,6 +481,7 @@ interface MailSenderOptions {
|
|
|
481
481
|
password: string;
|
|
482
482
|
authUser?: string;
|
|
483
483
|
secure?: boolean;
|
|
484
|
+
tlsRejectUnauthorized?: boolean;
|
|
484
485
|
}
|
|
485
486
|
interface SendResultWithRaw extends SendResult {
|
|
486
487
|
/** Raw RFC822 message bytes (for appending to Sent folder) */
|
|
@@ -1899,8 +1900,8 @@ declare function operatorPrefsStoragePath(): string;
|
|
|
1899
1900
|
*
|
|
1900
1901
|
* # What this is for
|
|
1901
1902
|
*
|
|
1902
|
-
* When a sub-agent replies into
|
|
1903
|
-
* (`claudecode@localhost` / `codex@localhost`), the dispatcher
|
|
1903
|
+
* When a sub-agent replies into a host bridge inbox
|
|
1904
|
+
* (`claudecode@localhost` / `codex@localhost` / etc.), the dispatcher
|
|
1904
1905
|
* historically had no way to react: bridges are skipped by
|
|
1905
1906
|
* `shouldWatch` because they belong to the human operator's host CLI,
|
|
1906
1907
|
* not to an automated worker. The mail would sit unread until the
|
|
@@ -1933,6 +1934,12 @@ declare function operatorPrefsStoragePath(): string;
|
|
|
1933
1934
|
* "sessionId": "019a2b3c-…",
|
|
1934
1935
|
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1935
1936
|
* "lastSeenMs": 1778905100000
|
|
1937
|
+
* },
|
|
1938
|
+
* "openclaw": {
|
|
1939
|
+
* "sessionId": "openclaw-session-key",
|
|
1940
|
+
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1941
|
+
* "lastSeenMs": 1778905000000,
|
|
1942
|
+
* "resumeMode": "wake"
|
|
1936
1943
|
* }
|
|
1937
1944
|
* }
|
|
1938
1945
|
* }
|
|
@@ -1963,14 +1970,24 @@ declare function operatorPrefsStoragePath(): string;
|
|
|
1963
1970
|
* that crashes the next reader. Same shape as `dispatcher-state.ts`.
|
|
1964
1971
|
*/
|
|
1965
1972
|
/** Canonical names for the host integrations that own bridge inboxes. */
|
|
1966
|
-
type HostName = 'claudecode' | 'codex';
|
|
1973
|
+
type HostName = 'claudecode' | 'codex' | 'openclaw' | 'gemini' | 'hermes';
|
|
1974
|
+
/**
|
|
1975
|
+
* How a host can be woken from a persisted session record.
|
|
1976
|
+
*
|
|
1977
|
+
* - `resume`: the host can resume a durable prior conversation/thread.
|
|
1978
|
+
* - `wake`: the host can target a live or recently known session key, but does
|
|
1979
|
+
* not guarantee full headless resume semantics.
|
|
1980
|
+
* - `wake-only`: the host can receive a wake notification, but the dispatcher
|
|
1981
|
+
* must not treat it as a resumed worker turn.
|
|
1982
|
+
*/
|
|
1983
|
+
type HostSessionResumeMode = 'resume' | 'wake' | 'wake-only';
|
|
1967
1984
|
/**
|
|
1968
1985
|
* A snapshot of one host CLI's last-known session. Persisted to disk
|
|
1969
1986
|
* by the mail-hook on every fire; loaded by the dispatcher when
|
|
1970
1987
|
* bridge mail arrives so a resume can be attempted.
|
|
1971
1988
|
*/
|
|
1972
1989
|
interface HostSession {
|
|
1973
|
-
/** Stable session_id from the host CLI
|
|
1990
|
+
/** Stable session_id/thread_id/session key from the host CLI/runtime. */
|
|
1974
1991
|
sessionId: string;
|
|
1975
1992
|
/** Wall-clock timestamp of the last hook fire on this session. */
|
|
1976
1993
|
lastSeenMs: number;
|
|
@@ -1980,6 +1997,10 @@ interface HostSession {
|
|
|
1980
1997
|
/** Optional: model name the host session was using, surfaced
|
|
1981
1998
|
* in logs for diagnostic context. */
|
|
1982
1999
|
model?: string;
|
|
2000
|
+
/** Optional: describes whether this host supports true resume or only wake. */
|
|
2001
|
+
resumeMode?: HostSessionResumeMode;
|
|
2002
|
+
/** Optional host-specific metadata. Must not contain secrets. */
|
|
2003
|
+
hostMetadata?: Record<string, unknown>;
|
|
1983
2004
|
}
|
|
1984
2005
|
/** Default freshness window — sessions older than this are skipped. */
|
|
1985
2006
|
declare const DEFAULT_SESSION_MAX_AGE_MS: number;
|
|
@@ -2017,6 +2038,38 @@ declare function forgetHostSession(host: HostName): void;
|
|
|
2017
2038
|
/** Exposed for tests + the `agenticmail status` diagnostic command. */
|
|
2018
2039
|
declare function hostSessionStoragePath(): string;
|
|
2019
2040
|
|
|
2041
|
+
type BridgeWakeError = 'session-expired' | 'sdk-missing' | 'timeout' | 'other';
|
|
2042
|
+
interface BridgeWakeResult {
|
|
2043
|
+
ok: boolean;
|
|
2044
|
+
text?: string;
|
|
2045
|
+
error?: BridgeWakeError;
|
|
2046
|
+
errorMessage?: string;
|
|
2047
|
+
durationMs?: number;
|
|
2048
|
+
}
|
|
2049
|
+
interface BridgeWakePromptArgs {
|
|
2050
|
+
bridgeName: string;
|
|
2051
|
+
uid: number;
|
|
2052
|
+
subject?: string;
|
|
2053
|
+
from?: string;
|
|
2054
|
+
preview?: string;
|
|
2055
|
+
}
|
|
2056
|
+
interface ResumeErrorClassificationOptions {
|
|
2057
|
+
expiredMarkers?: readonly string[];
|
|
2058
|
+
sdkMissingMarkers?: readonly string[];
|
|
2059
|
+
}
|
|
2060
|
+
declare const BRIDGE_OPERATOR_LIVE_WINDOW_MS = 30000;
|
|
2061
|
+
declare function bridgeWakeErrorMessage(err: unknown): string;
|
|
2062
|
+
declare function classifyResumeError(err: unknown, options?: ResumeErrorClassificationOptions): BridgeWakeError;
|
|
2063
|
+
declare function bridgeWakeLastSeenAgeMs(session: Pick<HostSession, 'lastSeenMs'> | null | undefined, nowMs?: number): number | null;
|
|
2064
|
+
declare function shouldSkipBridgeWakeForLiveOperator(session: Pick<HostSession, 'lastSeenMs'> | null | undefined, nowMs?: number, liveWindowMs?: number): boolean;
|
|
2065
|
+
/**
|
|
2066
|
+
* Build the prompt a host session sees on bridge wake. Host adapters
|
|
2067
|
+
* keep their own SDK resume call, but share this operator-facing
|
|
2068
|
+
* instruction shape so Claude Code, Codex, OpenClaw and later hosts
|
|
2069
|
+
* do not drift semantically.
|
|
2070
|
+
*/
|
|
2071
|
+
declare function composeBridgeWakePrompt(args: BridgeWakePromptArgs): string;
|
|
2072
|
+
|
|
2020
2073
|
/**
|
|
2021
2074
|
* SSRF-safe URL validation for the AgenticMail API base URL.
|
|
2022
2075
|
*
|
|
@@ -2624,4 +2677,4 @@ declare class AgentMemoryStore {
|
|
|
2624
2677
|
renderForPrompt(memory: AgentMemoryRead | null): string;
|
|
2625
2678
|
}
|
|
2626
2679
|
|
|
2627
|
-
export { AGENT_ROLES, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryFields, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, type CachedMessage, CloudflareClient, type CreateAgentOptions, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_SESSION_MAX_AGE_MS, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type HostName, type HostSession, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, type LinkAdvisory, type LocalSmtpConfig, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, type ParsedAttachment, type ParsedEmail, type ParsedSms, PathTraversalError, type PurchasedDomain, REDACTED, RELAY_PRESETS, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type TunnelConfig, TunnelManager, UnsafeApiUrlError, WARNING_THRESHOLD, type WatcherOptions, assertWithinBase, buildApiUrl, buildInboundSecurityAdvisory, classifyEmailRoute, closeDatabase, createTestDatabase, debug, debugWarn, ensureDataDir, extractVerificationCode, flushTelemetry, forgetHostSession, getDatabase, getOperatorEmail, getSmsProvider, hostSessionStoragePath, isInternalEmail, isSessionFresh, isValidPhoneNumber, loadHostSession, mapProviderSmsStatus, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, redactSmsConfig, resolveConfig, safeJoin, sanitizeEmail, saveConfig, saveHostSession, scanOutboundEmail, scoreEmail, setOperatorEmail, setTelemetryVersion, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|
|
2680
|
+
export { AGENT_ROLES, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryFields, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, BRIDGE_OPERATOR_LIVE_WINDOW_MS, type BridgeWakeError, type BridgeWakePromptArgs, type BridgeWakeResult, type CachedMessage, CloudflareClient, type CreateAgentOptions, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_SESSION_MAX_AGE_MS, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type HostName, type HostSession, type HostSessionResumeMode, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, type LinkAdvisory, type LocalSmtpConfig, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, type ParsedAttachment, type ParsedEmail, type ParsedSms, PathTraversalError, type PurchasedDomain, REDACTED, RELAY_PRESETS, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, type ResumeErrorClassificationOptions, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type TunnelConfig, TunnelManager, UnsafeApiUrlError, WARNING_THRESHOLD, type WatcherOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, buildInboundSecurityAdvisory, classifyEmailRoute, classifyResumeError, closeDatabase, composeBridgeWakePrompt, createTestDatabase, debug, debugWarn, ensureDataDir, extractVerificationCode, flushTelemetry, forgetHostSession, getDatabase, getOperatorEmail, getSmsProvider, hostSessionStoragePath, isInternalEmail, isSessionFresh, isValidPhoneNumber, loadHostSession, mapProviderSmsStatus, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, redactSmsConfig, resolveConfig, safeJoin, sanitizeEmail, saveConfig, saveHostSession, scanOutboundEmail, scoreEmail, setOperatorEmail, setTelemetryVersion, shouldSkipBridgeWakeForLiveOperator, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|
package/dist/index.js
CHANGED
|
@@ -24,8 +24,7 @@ var MailSender = class {
|
|
|
24
24
|
pass: options.password
|
|
25
25
|
},
|
|
26
26
|
tls: {
|
|
27
|
-
rejectUnauthorized:
|
|
28
|
-
// Local dev — no TLS
|
|
27
|
+
rejectUnauthorized: options.tlsRejectUnauthorized ?? true
|
|
29
28
|
},
|
|
30
29
|
connectionTimeout: 1e4,
|
|
31
30
|
// 10s to establish TCP connection
|
|
@@ -6447,6 +6446,69 @@ function hostSessionStoragePath() {
|
|
|
6447
6446
|
return storagePath();
|
|
6448
6447
|
}
|
|
6449
6448
|
|
|
6449
|
+
// src/host-bridge.ts
|
|
6450
|
+
var BRIDGE_OPERATOR_LIVE_WINDOW_MS = 3e4;
|
|
6451
|
+
var DEFAULT_EXPIRED_MARKERS = [
|
|
6452
|
+
"session not found",
|
|
6453
|
+
"invalid session",
|
|
6454
|
+
"session expired",
|
|
6455
|
+
"no such session",
|
|
6456
|
+
"unknown session",
|
|
6457
|
+
"thread not found",
|
|
6458
|
+
"invalid thread",
|
|
6459
|
+
"thread expired",
|
|
6460
|
+
"no such thread",
|
|
6461
|
+
"unknown thread"
|
|
6462
|
+
];
|
|
6463
|
+
var DEFAULT_SDK_MISSING_MARKERS = [
|
|
6464
|
+
"cannot find module",
|
|
6465
|
+
"could not be found",
|
|
6466
|
+
"command not found"
|
|
6467
|
+
];
|
|
6468
|
+
function bridgeWakeErrorMessage(err) {
|
|
6469
|
+
return err?.message ?? String(err);
|
|
6470
|
+
}
|
|
6471
|
+
function classifyResumeError(err, options = {}) {
|
|
6472
|
+
const msg = bridgeWakeErrorMessage(err).toLowerCase();
|
|
6473
|
+
const expiredMarkers = options.expiredMarkers ?? DEFAULT_EXPIRED_MARKERS;
|
|
6474
|
+
const sdkMissingMarkers = options.sdkMissingMarkers ?? DEFAULT_SDK_MISSING_MARKERS;
|
|
6475
|
+
if (expiredMarkers.some((marker) => msg.includes(marker))) return "session-expired";
|
|
6476
|
+
if (sdkMissingMarkers.some((marker) => msg.includes(marker))) return "sdk-missing";
|
|
6477
|
+
return "other";
|
|
6478
|
+
}
|
|
6479
|
+
function bridgeWakeLastSeenAgeMs(session, nowMs = Date.now()) {
|
|
6480
|
+
if (!session) return null;
|
|
6481
|
+
return nowMs - session.lastSeenMs;
|
|
6482
|
+
}
|
|
6483
|
+
function shouldSkipBridgeWakeForLiveOperator(session, nowMs = Date.now(), liveWindowMs = BRIDGE_OPERATOR_LIVE_WINDOW_MS) {
|
|
6484
|
+
const ageMs = bridgeWakeLastSeenAgeMs(session, nowMs);
|
|
6485
|
+
return ageMs !== null && ageMs < liveWindowMs;
|
|
6486
|
+
}
|
|
6487
|
+
function composeBridgeWakePrompt(args) {
|
|
6488
|
+
const subject = args.subject ?? "(no subject)";
|
|
6489
|
+
const from = args.from ?? "unknown";
|
|
6490
|
+
const preview = (args.preview ?? "").slice(0, 600);
|
|
6491
|
+
return [
|
|
6492
|
+
`\u{1F380} Bridge mail arrived \u2014 headless wake.`,
|
|
6493
|
+
"",
|
|
6494
|
+
`You are being resumed against your last session because new mail landed in your bridge inbox (${args.bridgeName}@localhost) and you weren't actively at the keyboard.`,
|
|
6495
|
+
"",
|
|
6496
|
+
`Trigger:`,
|
|
6497
|
+
` UID: ${args.uid}`,
|
|
6498
|
+
` From: ${from}`,
|
|
6499
|
+
` Subject: ${subject}`,
|
|
6500
|
+
` Preview: ${preview}`,
|
|
6501
|
+
"",
|
|
6502
|
+
`Read it with mcp__agenticmail__read_email({ uid: ${args.uid} }) and decide:`,
|
|
6503
|
+
` \xB7 Does it need a reply from YOU (the operator's session)? Reply via mcp__agenticmail__reply_email.`,
|
|
6504
|
+
` \xB7 Does it need a teammate to act? Forward / re-route by replying with wake: ["<teammate>"].`,
|
|
6505
|
+
` \xB7 Is it [NEEDS OPERATOR] / [BLOCKED]? Then it's actually for the human \u2014 mark it unread, and the operator will see it on their next keystroke.`,
|
|
6506
|
+
` \xB7 Is it FYI noise? mark_read and exit.`,
|
|
6507
|
+
"",
|
|
6508
|
+
`Keep this turn SHORT. You're being resumed to handle ONE piece of mail, not to continue the prior conversation.`
|
|
6509
|
+
].join("\n");
|
|
6510
|
+
}
|
|
6511
|
+
|
|
6450
6512
|
// src/util/safe-url.ts
|
|
6451
6513
|
var UnsafeApiUrlError = class extends Error {
|
|
6452
6514
|
constructor(raw, reason) {
|
|
@@ -8138,6 +8200,7 @@ export {
|
|
|
8138
8200
|
AgentDeletionService,
|
|
8139
8201
|
AgentMemoryStore,
|
|
8140
8202
|
AgenticMailClient,
|
|
8203
|
+
BRIDGE_OPERATOR_LIVE_WINDOW_MS,
|
|
8141
8204
|
CloudflareClient,
|
|
8142
8205
|
DEFAULT_AGENT_NAME,
|
|
8143
8206
|
DEFAULT_AGENT_ROLE,
|
|
@@ -8168,10 +8231,14 @@ export {
|
|
|
8168
8231
|
UnsafeApiUrlError,
|
|
8169
8232
|
WARNING_THRESHOLD,
|
|
8170
8233
|
assertWithinBase,
|
|
8234
|
+
bridgeWakeErrorMessage,
|
|
8235
|
+
bridgeWakeLastSeenAgeMs,
|
|
8171
8236
|
buildApiUrl,
|
|
8172
8237
|
buildInboundSecurityAdvisory,
|
|
8173
8238
|
classifyEmailRoute,
|
|
8239
|
+
classifyResumeError,
|
|
8174
8240
|
closeDatabase,
|
|
8241
|
+
composeBridgeWakePrompt,
|
|
8175
8242
|
createTestDatabase,
|
|
8176
8243
|
debug,
|
|
8177
8244
|
debugWarn,
|
|
@@ -8207,6 +8274,7 @@ export {
|
|
|
8207
8274
|
scoreEmail,
|
|
8208
8275
|
setOperatorEmail,
|
|
8209
8276
|
setTelemetryVersion,
|
|
8277
|
+
shouldSkipBridgeWakeForLiveOperator,
|
|
8210
8278
|
startRelayBridge,
|
|
8211
8279
|
threadIdFor,
|
|
8212
8280
|
tryJoin,
|