@agenticmail/core 0.9.5 → 0.9.7
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 +375 -205
- package/dist/index.d.cts +192 -1
- package/dist/index.d.ts +192 -1
- package/dist/index.js +356 -195
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -200,6 +200,20 @@ interface AgenticMailConfig {
|
|
|
200
200
|
provider?: 'google_voice';
|
|
201
201
|
configuredAt?: string;
|
|
202
202
|
};
|
|
203
|
+
/**
|
|
204
|
+
* Operator's notification address. Used by the dispatcher's
|
|
205
|
+
* bridge-escalation path: when sub-agents mail a bridge inbox AND
|
|
206
|
+
* no fresh host session is available for a headless resume, the
|
|
207
|
+
* API forwards a digest to this address so the operator gets a
|
|
208
|
+
* phone push (via Gmail / Apple Mail / whichever app handles
|
|
209
|
+
* their address). Set during install — the host agent (claude /
|
|
210
|
+
* codex) collects it via the `setup_operator_email` MCP tool
|
|
211
|
+
* during bootstrap and persists it here.
|
|
212
|
+
*
|
|
213
|
+
* Optional. When unset, escalations are still recorded as a
|
|
214
|
+
* system event (visible in the web UI) but no email is sent.
|
|
215
|
+
*/
|
|
216
|
+
operatorEmail?: string;
|
|
203
217
|
masterKey: string;
|
|
204
218
|
dataDir: string;
|
|
205
219
|
}
|
|
@@ -1493,6 +1507,28 @@ declare class SmsManager {
|
|
|
1493
1507
|
getSmsConfig(agentId: string): SmsConfig | null;
|
|
1494
1508
|
/** Save SMS config to agent metadata */
|
|
1495
1509
|
saveSmsConfig(agentId: string, config: SmsConfig): void;
|
|
1510
|
+
/**
|
|
1511
|
+
* Resolve the operator's "where do I get pinged" address from an
|
|
1512
|
+
* agent's SMS config. Used by the dispatcher's bridge-escalation
|
|
1513
|
+
* path: when sub-agents mail a bridge with no fresh host session
|
|
1514
|
+
* available, we email the operator a digest at this address. Their
|
|
1515
|
+
* phone's Gmail push notification surfaces it within seconds —
|
|
1516
|
+
* effectively a free, programmatic alert channel.
|
|
1517
|
+
*
|
|
1518
|
+
* Returns the configured `forwardingEmail` (the same Gmail Google
|
|
1519
|
+
* Voice forwards inbound SMS to, which the operator already has
|
|
1520
|
+
* push notifications enabled for) when SMS is configured AND
|
|
1521
|
+
* enabled. Returns null otherwise — caller falls through to a
|
|
1522
|
+
* silent log + system event.
|
|
1523
|
+
*
|
|
1524
|
+
* Why we don't try real-SMS delivery yet: Google Voice's
|
|
1525
|
+
* `<number>@txt.voice.google.com` email-to-SMS gateway was
|
|
1526
|
+
* deprecated by Google years ago. A future `carrier` field on
|
|
1527
|
+
* SmsConfig (Verizon vtext.com / AT&T txt.att.net / etc) will let
|
|
1528
|
+
* the operator opt into actual SMS, but that's a follow-up — the
|
|
1529
|
+
* email path already gets the operator a phone notification.
|
|
1530
|
+
*/
|
|
1531
|
+
getAlertEmail(agentId: string): string | null;
|
|
1496
1532
|
/** Remove SMS config from agent metadata */
|
|
1497
1533
|
removeSmsConfig(agentId: string): void;
|
|
1498
1534
|
/** Record an inbound SMS (parsed from email) */
|
|
@@ -1764,6 +1800,161 @@ declare function redactSecret(value: unknown): string;
|
|
|
1764
1800
|
*/
|
|
1765
1801
|
declare function redactObject<T>(input: T, _depth?: number): T;
|
|
1766
1802
|
|
|
1803
|
+
/**
|
|
1804
|
+
* Operator preferences — small per-installation knobs that don't fit
|
|
1805
|
+
* cleanly in the bootstrap-managed `~/.agenticmail/config.json`.
|
|
1806
|
+
*
|
|
1807
|
+
* Currently just `operatorEmail` for bridge-escalation alerts. The
|
|
1808
|
+
* intent is a tiny mutable surface the host agent (claudecode /
|
|
1809
|
+
* codex) can update via MCP without touching the read-only-after-
|
|
1810
|
+
* bootstrap config blob.
|
|
1811
|
+
*
|
|
1812
|
+
* # Storage
|
|
1813
|
+
*
|
|
1814
|
+
* `~/.agenticmail/operator-prefs.json`:
|
|
1815
|
+
*
|
|
1816
|
+
* ```json
|
|
1817
|
+
* { "version": 1, "operatorEmail": "ope@gmail.com" }
|
|
1818
|
+
* ```
|
|
1819
|
+
*
|
|
1820
|
+
* Atomic writes (tmp + rename), tolerant of missing / corrupt
|
|
1821
|
+
* files (returns null and lets the caller decide). Lazy path
|
|
1822
|
+
* resolution so tests can override `homedir()` per-test.
|
|
1823
|
+
*/
|
|
1824
|
+
/** Returns the operator's escalation email, or null if not set. */
|
|
1825
|
+
declare function getOperatorEmail(): string | null;
|
|
1826
|
+
/**
|
|
1827
|
+
* Set (or clear) the operator's escalation email. Pass `null` /
|
|
1828
|
+
* empty string to clear. Returns the canonical stored value (trimmed,
|
|
1829
|
+
* lowercased local-part preserved as-is per RFC 5321).
|
|
1830
|
+
*/
|
|
1831
|
+
declare function setOperatorEmail(email: string | null): string | null;
|
|
1832
|
+
/** Exposed for tests + diagnostic CLI commands. */
|
|
1833
|
+
declare function operatorPrefsStoragePath(): string;
|
|
1834
|
+
|
|
1835
|
+
/**
|
|
1836
|
+
* Persisted host-session registry.
|
|
1837
|
+
*
|
|
1838
|
+
* # What this is for
|
|
1839
|
+
*
|
|
1840
|
+
* When a sub-agent replies into the host bridge inbox
|
|
1841
|
+
* (`claudecode@localhost` / `codex@localhost`), the dispatcher
|
|
1842
|
+
* historically had no way to react: bridges are skipped by
|
|
1843
|
+
* `shouldWatch` because they belong to the human operator's host CLI,
|
|
1844
|
+
* not to an automated worker. The mail would sit unread until the
|
|
1845
|
+
* operator opened their CLI again — sometimes hours later, sometimes
|
|
1846
|
+
* never that day.
|
|
1847
|
+
*
|
|
1848
|
+
* This module is the missing link. Every time the host's mail-hook
|
|
1849
|
+
* fires (on `SessionStart` / `UserPromptSubmit` / `Stop`), it captures
|
|
1850
|
+
* the host CLI's current `session_id` and persists it here. The
|
|
1851
|
+
* dispatcher can then check "what session was running last?" and
|
|
1852
|
+
* attempt a headless resume against it when bridge mail arrives —
|
|
1853
|
+
* the same way Telegram bridges (Fola, etc.) keep a session alive
|
|
1854
|
+
* between bursts of activity.
|
|
1855
|
+
*
|
|
1856
|
+
* # The file
|
|
1857
|
+
*
|
|
1858
|
+
* `~/.agenticmail/host-sessions.json`:
|
|
1859
|
+
*
|
|
1860
|
+
* ```json
|
|
1861
|
+
* {
|
|
1862
|
+
* "version": 1,
|
|
1863
|
+
* "sessions": {
|
|
1864
|
+
* "claudecode": {
|
|
1865
|
+
* "sessionId": "01a2b3c4-…",
|
|
1866
|
+
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1867
|
+
* "lastSeenMs": 1778905200000,
|
|
1868
|
+
* "model": "claude-sonnet-4-5"
|
|
1869
|
+
* },
|
|
1870
|
+
* "codex": {
|
|
1871
|
+
* "sessionId": "019a2b3c-…",
|
|
1872
|
+
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1873
|
+
* "lastSeenMs": 1778905100000
|
|
1874
|
+
* }
|
|
1875
|
+
* }
|
|
1876
|
+
* }
|
|
1877
|
+
* ```
|
|
1878
|
+
*
|
|
1879
|
+
* Per host we keep ONE session — the most recent. If the operator
|
|
1880
|
+
* runs `claude` twice (e.g. one window for "general", one for "build
|
|
1881
|
+
* the LinkedIn clone"), we only track the last-active one. The
|
|
1882
|
+
* bridge resume always targets whichever was active most recently;
|
|
1883
|
+
* the operator's intuition matches that ("I just left my Claude
|
|
1884
|
+
* Code session a minute ago and the bridge ought to be able to
|
|
1885
|
+
* resume it").
|
|
1886
|
+
*
|
|
1887
|
+
* # Freshness semantics
|
|
1888
|
+
*
|
|
1889
|
+
* A session is considered "resumable" if `lastSeenMs` is within the
|
|
1890
|
+
* last 24 hours. Older than that, both Anthropic and OpenAI tend to
|
|
1891
|
+
* have evicted the session from their resume cache (cost-driven
|
|
1892
|
+
* decision; observed empirically). The dispatcher uses
|
|
1893
|
+
* `isSessionFresh(session, maxAgeMs)` to gate the resume attempt and
|
|
1894
|
+
* fall through to SMS / persistent storage when stale.
|
|
1895
|
+
*
|
|
1896
|
+
* # Atomic writes
|
|
1897
|
+
*
|
|
1898
|
+
* The mail-hook can fire concurrently with another hook on a
|
|
1899
|
+
* different host CLI window. The write path goes through a tmp file
|
|
1900
|
+
* + rename so a torn write can never leave a half-valid JSON file
|
|
1901
|
+
* that crashes the next reader. Same shape as `dispatcher-state.ts`.
|
|
1902
|
+
*/
|
|
1903
|
+
/** Canonical names for the host integrations that own bridge inboxes. */
|
|
1904
|
+
type HostName = 'claudecode' | 'codex';
|
|
1905
|
+
/**
|
|
1906
|
+
* A snapshot of one host CLI's last-known session. Persisted to disk
|
|
1907
|
+
* by the mail-hook on every fire; loaded by the dispatcher when
|
|
1908
|
+
* bridge mail arrives so a resume can be attempted.
|
|
1909
|
+
*/
|
|
1910
|
+
interface HostSession {
|
|
1911
|
+
/** Stable session_id from the host CLI (Claude Code or Codex). */
|
|
1912
|
+
sessionId: string;
|
|
1913
|
+
/** Wall-clock timestamp of the last hook fire on this session. */
|
|
1914
|
+
lastSeenMs: number;
|
|
1915
|
+
/** Optional: project cwd the host CLI was opened in. Used by
|
|
1916
|
+
* resume to spawn the headless turn in the right directory. */
|
|
1917
|
+
workspace?: string;
|
|
1918
|
+
/** Optional: model name the host session was using, surfaced
|
|
1919
|
+
* in logs for diagnostic context. */
|
|
1920
|
+
model?: string;
|
|
1921
|
+
}
|
|
1922
|
+
/** Default freshness window — sessions older than this are skipped. */
|
|
1923
|
+
declare const DEFAULT_SESSION_MAX_AGE_MS: number;
|
|
1924
|
+
/**
|
|
1925
|
+
* Record the current host session. Called from the mail-hook on
|
|
1926
|
+
* every fire with the `session_id` the host passed in. Updates the
|
|
1927
|
+
* existing record for that host or creates one — last write wins.
|
|
1928
|
+
*
|
|
1929
|
+
* Failures are swallowed so the mail-hook never crashes the host CLI
|
|
1930
|
+
* over a disk write. The bridge-wake path tolerates a missing record
|
|
1931
|
+
* (falls through to SMS).
|
|
1932
|
+
*/
|
|
1933
|
+
declare function saveHostSession(host: HostName, session: Omit<HostSession, 'lastSeenMs'>): void;
|
|
1934
|
+
/**
|
|
1935
|
+
* Look up the most-recent session for a host. Returns null when no
|
|
1936
|
+
* record exists OR the record is older than `maxAgeMs` (default 24h).
|
|
1937
|
+
*
|
|
1938
|
+
* The age gate exists because both providers expire resume tokens
|
|
1939
|
+
* after roughly a day; attempting resume against a stale token is
|
|
1940
|
+
* almost always slower than starting fresh.
|
|
1941
|
+
*/
|
|
1942
|
+
declare function loadHostSession(host: HostName, maxAgeMs?: number): HostSession | null;
|
|
1943
|
+
/**
|
|
1944
|
+
* Pure freshness predicate — exported for tests + for callers that
|
|
1945
|
+
* want to read the raw record (e.g. to print "last seen 2 hours ago"
|
|
1946
|
+
* in a diagnostic command).
|
|
1947
|
+
*/
|
|
1948
|
+
declare function isSessionFresh(session: HostSession, maxAgeMs?: number): boolean;
|
|
1949
|
+
/**
|
|
1950
|
+
* Clear a host's recorded session. Called when the operator runs
|
|
1951
|
+
* `agenticmail-<host> uninstall` so the next install doesn't try to
|
|
1952
|
+
* resume a session that no longer exists.
|
|
1953
|
+
*/
|
|
1954
|
+
declare function forgetHostSession(host: HostName): void;
|
|
1955
|
+
/** Exposed for tests + the `agenticmail status` diagnostic command. */
|
|
1956
|
+
declare function hostSessionStoragePath(): string;
|
|
1957
|
+
|
|
1767
1958
|
/**
|
|
1768
1959
|
* SSRF-safe URL validation for the AgenticMail API base URL.
|
|
1769
1960
|
*
|
|
@@ -2371,4 +2562,4 @@ declare class AgentMemoryStore {
|
|
|
2371
2562
|
renderForPrompt(memory: AgentMemoryRead | null): string;
|
|
2372
2563
|
}
|
|
2373
2564
|
|
|
2374
|
-
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, 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 InboundEmail, 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, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, 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, getDatabase, isInternalEmail, isValidPhoneNumber, normalizeAddress, normalizePhoneNumber, normalizeSubject, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, resolveConfig, safeJoin, sanitizeEmail, saveConfig, scanOutboundEmail, scoreEmail, setTelemetryVersion, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|
|
2565
|
+
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 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, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, 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, hostSessionStoragePath, isInternalEmail, isSessionFresh, isValidPhoneNumber, loadHostSession, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, resolveConfig, safeJoin, sanitizeEmail, saveConfig, saveHostSession, scanOutboundEmail, scoreEmail, setOperatorEmail, setTelemetryVersion, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|
package/dist/index.d.ts
CHANGED
|
@@ -200,6 +200,20 @@ interface AgenticMailConfig {
|
|
|
200
200
|
provider?: 'google_voice';
|
|
201
201
|
configuredAt?: string;
|
|
202
202
|
};
|
|
203
|
+
/**
|
|
204
|
+
* Operator's notification address. Used by the dispatcher's
|
|
205
|
+
* bridge-escalation path: when sub-agents mail a bridge inbox AND
|
|
206
|
+
* no fresh host session is available for a headless resume, the
|
|
207
|
+
* API forwards a digest to this address so the operator gets a
|
|
208
|
+
* phone push (via Gmail / Apple Mail / whichever app handles
|
|
209
|
+
* their address). Set during install — the host agent (claude /
|
|
210
|
+
* codex) collects it via the `setup_operator_email` MCP tool
|
|
211
|
+
* during bootstrap and persists it here.
|
|
212
|
+
*
|
|
213
|
+
* Optional. When unset, escalations are still recorded as a
|
|
214
|
+
* system event (visible in the web UI) but no email is sent.
|
|
215
|
+
*/
|
|
216
|
+
operatorEmail?: string;
|
|
203
217
|
masterKey: string;
|
|
204
218
|
dataDir: string;
|
|
205
219
|
}
|
|
@@ -1493,6 +1507,28 @@ declare class SmsManager {
|
|
|
1493
1507
|
getSmsConfig(agentId: string): SmsConfig | null;
|
|
1494
1508
|
/** Save SMS config to agent metadata */
|
|
1495
1509
|
saveSmsConfig(agentId: string, config: SmsConfig): void;
|
|
1510
|
+
/**
|
|
1511
|
+
* Resolve the operator's "where do I get pinged" address from an
|
|
1512
|
+
* agent's SMS config. Used by the dispatcher's bridge-escalation
|
|
1513
|
+
* path: when sub-agents mail a bridge with no fresh host session
|
|
1514
|
+
* available, we email the operator a digest at this address. Their
|
|
1515
|
+
* phone's Gmail push notification surfaces it within seconds —
|
|
1516
|
+
* effectively a free, programmatic alert channel.
|
|
1517
|
+
*
|
|
1518
|
+
* Returns the configured `forwardingEmail` (the same Gmail Google
|
|
1519
|
+
* Voice forwards inbound SMS to, which the operator already has
|
|
1520
|
+
* push notifications enabled for) when SMS is configured AND
|
|
1521
|
+
* enabled. Returns null otherwise — caller falls through to a
|
|
1522
|
+
* silent log + system event.
|
|
1523
|
+
*
|
|
1524
|
+
* Why we don't try real-SMS delivery yet: Google Voice's
|
|
1525
|
+
* `<number>@txt.voice.google.com` email-to-SMS gateway was
|
|
1526
|
+
* deprecated by Google years ago. A future `carrier` field on
|
|
1527
|
+
* SmsConfig (Verizon vtext.com / AT&T txt.att.net / etc) will let
|
|
1528
|
+
* the operator opt into actual SMS, but that's a follow-up — the
|
|
1529
|
+
* email path already gets the operator a phone notification.
|
|
1530
|
+
*/
|
|
1531
|
+
getAlertEmail(agentId: string): string | null;
|
|
1496
1532
|
/** Remove SMS config from agent metadata */
|
|
1497
1533
|
removeSmsConfig(agentId: string): void;
|
|
1498
1534
|
/** Record an inbound SMS (parsed from email) */
|
|
@@ -1764,6 +1800,161 @@ declare function redactSecret(value: unknown): string;
|
|
|
1764
1800
|
*/
|
|
1765
1801
|
declare function redactObject<T>(input: T, _depth?: number): T;
|
|
1766
1802
|
|
|
1803
|
+
/**
|
|
1804
|
+
* Operator preferences — small per-installation knobs that don't fit
|
|
1805
|
+
* cleanly in the bootstrap-managed `~/.agenticmail/config.json`.
|
|
1806
|
+
*
|
|
1807
|
+
* Currently just `operatorEmail` for bridge-escalation alerts. The
|
|
1808
|
+
* intent is a tiny mutable surface the host agent (claudecode /
|
|
1809
|
+
* codex) can update via MCP without touching the read-only-after-
|
|
1810
|
+
* bootstrap config blob.
|
|
1811
|
+
*
|
|
1812
|
+
* # Storage
|
|
1813
|
+
*
|
|
1814
|
+
* `~/.agenticmail/operator-prefs.json`:
|
|
1815
|
+
*
|
|
1816
|
+
* ```json
|
|
1817
|
+
* { "version": 1, "operatorEmail": "ope@gmail.com" }
|
|
1818
|
+
* ```
|
|
1819
|
+
*
|
|
1820
|
+
* Atomic writes (tmp + rename), tolerant of missing / corrupt
|
|
1821
|
+
* files (returns null and lets the caller decide). Lazy path
|
|
1822
|
+
* resolution so tests can override `homedir()` per-test.
|
|
1823
|
+
*/
|
|
1824
|
+
/** Returns the operator's escalation email, or null if not set. */
|
|
1825
|
+
declare function getOperatorEmail(): string | null;
|
|
1826
|
+
/**
|
|
1827
|
+
* Set (or clear) the operator's escalation email. Pass `null` /
|
|
1828
|
+
* empty string to clear. Returns the canonical stored value (trimmed,
|
|
1829
|
+
* lowercased local-part preserved as-is per RFC 5321).
|
|
1830
|
+
*/
|
|
1831
|
+
declare function setOperatorEmail(email: string | null): string | null;
|
|
1832
|
+
/** Exposed for tests + diagnostic CLI commands. */
|
|
1833
|
+
declare function operatorPrefsStoragePath(): string;
|
|
1834
|
+
|
|
1835
|
+
/**
|
|
1836
|
+
* Persisted host-session registry.
|
|
1837
|
+
*
|
|
1838
|
+
* # What this is for
|
|
1839
|
+
*
|
|
1840
|
+
* When a sub-agent replies into the host bridge inbox
|
|
1841
|
+
* (`claudecode@localhost` / `codex@localhost`), the dispatcher
|
|
1842
|
+
* historically had no way to react: bridges are skipped by
|
|
1843
|
+
* `shouldWatch` because they belong to the human operator's host CLI,
|
|
1844
|
+
* not to an automated worker. The mail would sit unread until the
|
|
1845
|
+
* operator opened their CLI again — sometimes hours later, sometimes
|
|
1846
|
+
* never that day.
|
|
1847
|
+
*
|
|
1848
|
+
* This module is the missing link. Every time the host's mail-hook
|
|
1849
|
+
* fires (on `SessionStart` / `UserPromptSubmit` / `Stop`), it captures
|
|
1850
|
+
* the host CLI's current `session_id` and persists it here. The
|
|
1851
|
+
* dispatcher can then check "what session was running last?" and
|
|
1852
|
+
* attempt a headless resume against it when bridge mail arrives —
|
|
1853
|
+
* the same way Telegram bridges (Fola, etc.) keep a session alive
|
|
1854
|
+
* between bursts of activity.
|
|
1855
|
+
*
|
|
1856
|
+
* # The file
|
|
1857
|
+
*
|
|
1858
|
+
* `~/.agenticmail/host-sessions.json`:
|
|
1859
|
+
*
|
|
1860
|
+
* ```json
|
|
1861
|
+
* {
|
|
1862
|
+
* "version": 1,
|
|
1863
|
+
* "sessions": {
|
|
1864
|
+
* "claudecode": {
|
|
1865
|
+
* "sessionId": "01a2b3c4-…",
|
|
1866
|
+
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1867
|
+
* "lastSeenMs": 1778905200000,
|
|
1868
|
+
* "model": "claude-sonnet-4-5"
|
|
1869
|
+
* },
|
|
1870
|
+
* "codex": {
|
|
1871
|
+
* "sessionId": "019a2b3c-…",
|
|
1872
|
+
* "workspace": "/Users/ope/Desktop/facebook-project",
|
|
1873
|
+
* "lastSeenMs": 1778905100000
|
|
1874
|
+
* }
|
|
1875
|
+
* }
|
|
1876
|
+
* }
|
|
1877
|
+
* ```
|
|
1878
|
+
*
|
|
1879
|
+
* Per host we keep ONE session — the most recent. If the operator
|
|
1880
|
+
* runs `claude` twice (e.g. one window for "general", one for "build
|
|
1881
|
+
* the LinkedIn clone"), we only track the last-active one. The
|
|
1882
|
+
* bridge resume always targets whichever was active most recently;
|
|
1883
|
+
* the operator's intuition matches that ("I just left my Claude
|
|
1884
|
+
* Code session a minute ago and the bridge ought to be able to
|
|
1885
|
+
* resume it").
|
|
1886
|
+
*
|
|
1887
|
+
* # Freshness semantics
|
|
1888
|
+
*
|
|
1889
|
+
* A session is considered "resumable" if `lastSeenMs` is within the
|
|
1890
|
+
* last 24 hours. Older than that, both Anthropic and OpenAI tend to
|
|
1891
|
+
* have evicted the session from their resume cache (cost-driven
|
|
1892
|
+
* decision; observed empirically). The dispatcher uses
|
|
1893
|
+
* `isSessionFresh(session, maxAgeMs)` to gate the resume attempt and
|
|
1894
|
+
* fall through to SMS / persistent storage when stale.
|
|
1895
|
+
*
|
|
1896
|
+
* # Atomic writes
|
|
1897
|
+
*
|
|
1898
|
+
* The mail-hook can fire concurrently with another hook on a
|
|
1899
|
+
* different host CLI window. The write path goes through a tmp file
|
|
1900
|
+
* + rename so a torn write can never leave a half-valid JSON file
|
|
1901
|
+
* that crashes the next reader. Same shape as `dispatcher-state.ts`.
|
|
1902
|
+
*/
|
|
1903
|
+
/** Canonical names for the host integrations that own bridge inboxes. */
|
|
1904
|
+
type HostName = 'claudecode' | 'codex';
|
|
1905
|
+
/**
|
|
1906
|
+
* A snapshot of one host CLI's last-known session. Persisted to disk
|
|
1907
|
+
* by the mail-hook on every fire; loaded by the dispatcher when
|
|
1908
|
+
* bridge mail arrives so a resume can be attempted.
|
|
1909
|
+
*/
|
|
1910
|
+
interface HostSession {
|
|
1911
|
+
/** Stable session_id from the host CLI (Claude Code or Codex). */
|
|
1912
|
+
sessionId: string;
|
|
1913
|
+
/** Wall-clock timestamp of the last hook fire on this session. */
|
|
1914
|
+
lastSeenMs: number;
|
|
1915
|
+
/** Optional: project cwd the host CLI was opened in. Used by
|
|
1916
|
+
* resume to spawn the headless turn in the right directory. */
|
|
1917
|
+
workspace?: string;
|
|
1918
|
+
/** Optional: model name the host session was using, surfaced
|
|
1919
|
+
* in logs for diagnostic context. */
|
|
1920
|
+
model?: string;
|
|
1921
|
+
}
|
|
1922
|
+
/** Default freshness window — sessions older than this are skipped. */
|
|
1923
|
+
declare const DEFAULT_SESSION_MAX_AGE_MS: number;
|
|
1924
|
+
/**
|
|
1925
|
+
* Record the current host session. Called from the mail-hook on
|
|
1926
|
+
* every fire with the `session_id` the host passed in. Updates the
|
|
1927
|
+
* existing record for that host or creates one — last write wins.
|
|
1928
|
+
*
|
|
1929
|
+
* Failures are swallowed so the mail-hook never crashes the host CLI
|
|
1930
|
+
* over a disk write. The bridge-wake path tolerates a missing record
|
|
1931
|
+
* (falls through to SMS).
|
|
1932
|
+
*/
|
|
1933
|
+
declare function saveHostSession(host: HostName, session: Omit<HostSession, 'lastSeenMs'>): void;
|
|
1934
|
+
/**
|
|
1935
|
+
* Look up the most-recent session for a host. Returns null when no
|
|
1936
|
+
* record exists OR the record is older than `maxAgeMs` (default 24h).
|
|
1937
|
+
*
|
|
1938
|
+
* The age gate exists because both providers expire resume tokens
|
|
1939
|
+
* after roughly a day; attempting resume against a stale token is
|
|
1940
|
+
* almost always slower than starting fresh.
|
|
1941
|
+
*/
|
|
1942
|
+
declare function loadHostSession(host: HostName, maxAgeMs?: number): HostSession | null;
|
|
1943
|
+
/**
|
|
1944
|
+
* Pure freshness predicate — exported for tests + for callers that
|
|
1945
|
+
* want to read the raw record (e.g. to print "last seen 2 hours ago"
|
|
1946
|
+
* in a diagnostic command).
|
|
1947
|
+
*/
|
|
1948
|
+
declare function isSessionFresh(session: HostSession, maxAgeMs?: number): boolean;
|
|
1949
|
+
/**
|
|
1950
|
+
* Clear a host's recorded session. Called when the operator runs
|
|
1951
|
+
* `agenticmail-<host> uninstall` so the next install doesn't try to
|
|
1952
|
+
* resume a session that no longer exists.
|
|
1953
|
+
*/
|
|
1954
|
+
declare function forgetHostSession(host: HostName): void;
|
|
1955
|
+
/** Exposed for tests + the `agenticmail status` diagnostic command. */
|
|
1956
|
+
declare function hostSessionStoragePath(): string;
|
|
1957
|
+
|
|
1767
1958
|
/**
|
|
1768
1959
|
* SSRF-safe URL validation for the AgenticMail API base URL.
|
|
1769
1960
|
*
|
|
@@ -2371,4 +2562,4 @@ declare class AgentMemoryStore {
|
|
|
2371
2562
|
renderForPrompt(memory: AgentMemoryRead | null): string;
|
|
2372
2563
|
}
|
|
2373
2564
|
|
|
2374
|
-
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, 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 InboundEmail, 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, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, 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, getDatabase, isInternalEmail, isValidPhoneNumber, normalizeAddress, normalizePhoneNumber, normalizeSubject, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, resolveConfig, safeJoin, sanitizeEmail, saveConfig, scanOutboundEmail, scoreEmail, setTelemetryVersion, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|
|
2565
|
+
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 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, ServiceManager, type ServiceStatus, type SetupConfig, SetupManager, type SetupResult, type Severity, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, 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, hostSessionStoragePath, isInternalEmail, isSessionFresh, isValidPhoneNumber, loadHostSession, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, parseEmail, parseGoogleVoiceSms, recordToolCall, redactObject, redactSecret, resolveConfig, safeJoin, sanitizeEmail, saveConfig, saveHostSession, scanOutboundEmail, scoreEmail, setOperatorEmail, setTelemetryVersion, startRelayBridge, threadIdFor, tryJoin, validateApiUrl };
|