@agenticmail/core 0.5.38 → 0.5.40

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.d.ts CHANGED
@@ -1392,6 +1392,27 @@ declare class SmsPoller {
1392
1392
  private pollOnce;
1393
1393
  }
1394
1394
 
1395
+ /**
1396
+ * AgenticMail Anonymous Telemetry
1397
+ *
1398
+ * Collects anonymous usage counts to help improve the product.
1399
+ * NO personal data, API keys, emails, or content is ever collected.
1400
+ *
1401
+ * Opt out: set AGENTICMAIL_TELEMETRY=0 or DO_NOT_TRACK=1
1402
+ *
1403
+ * What we collect:
1404
+ * - Tool call counts (which tools are popular)
1405
+ * - Package version
1406
+ * - Anonymous install ID (random UUID, no PII)
1407
+ * - OS platform (e.g. "darwin", "linux")
1408
+ */
1409
+ /** Set the package version for telemetry events */
1410
+ declare function setTelemetryVersion(version: string): void;
1411
+ /** Record a tool call (fire-and-forget, never throws) */
1412
+ declare function recordToolCall(toolName: string): void;
1413
+ /** Flush remaining events on process exit */
1414
+ declare function flushTelemetry(): void;
1415
+
1395
1416
  declare function debug(tag: string, message: string): void;
1396
1417
  declare function debugWarn(tag: string, message: string): void;
1397
1418
 
@@ -1640,4 +1661,4 @@ declare class SetupManager {
1640
1661
  isInitialized(): boolean;
1641
1662
  }
1642
1663
 
1643
- export { AGENT_ROLES, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, CloudflareClient, type CreateAgentOptions, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DNSConfigurator, 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, 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, type PurchasedDomain, RELAY_PRESETS, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, SPAM_THRESHOLD, 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, type TunnelConfig, TunnelManager, WARNING_THRESHOLD, type WatcherOptions, buildInboundSecurityAdvisory, closeDatabase, createTestDatabase, debug, debugWarn, ensureDataDir, extractVerificationCode, getDatabase, isInternalEmail, isValidPhoneNumber, normalizePhoneNumber, parseEmail, parseGoogleVoiceSms, resolveConfig, sanitizeEmail, saveConfig, scanOutboundEmail, scoreEmail, startRelayBridge };
1664
+ export { AGENT_ROLES, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, CloudflareClient, type CreateAgentOptions, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DNSConfigurator, 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, 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, type PurchasedDomain, RELAY_PRESETS, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, SPAM_THRESHOLD, 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, type TunnelConfig, TunnelManager, WARNING_THRESHOLD, type WatcherOptions, buildInboundSecurityAdvisory, closeDatabase, createTestDatabase, debug, debugWarn, ensureDataDir, extractVerificationCode, flushTelemetry, getDatabase, isInternalEmail, isValidPhoneNumber, normalizePhoneNumber, parseEmail, parseGoogleVoiceSms, recordToolCall, resolveConfig, sanitizeEmail, saveConfig, scanOutboundEmail, scoreEmail, setTelemetryVersion, startRelayBridge };
package/dist/index.js CHANGED
@@ -859,14 +859,14 @@ var StalwartAdmin = class {
859
859
  if (!isValidDomain(domain)) {
860
860
  throw new Error(`Invalid domain format: "${domain}"`);
861
861
  }
862
- const { readFileSync: readFileSync4, writeFileSync: writeFileSync5 } = await import("fs");
863
- const { homedir: homedir8 } = await import("os");
864
- const { join: join9 } = await import("path");
865
- const configPath = join9(homedir8(), ".agenticmail", "stalwart.toml");
862
+ const { readFileSync: readFileSync5, writeFileSync: writeFileSync6 } = await import("fs");
863
+ const { homedir: homedir9 } = await import("os");
864
+ const { join: join10 } = await import("path");
865
+ const configPath = join10(homedir9(), ".agenticmail", "stalwart.toml");
866
866
  try {
867
- let config = readFileSync4(configPath, "utf-8");
867
+ let config = readFileSync5(configPath, "utf-8");
868
868
  config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
869
- writeFileSync5(configPath, config);
869
+ writeFileSync6(configPath, config);
870
870
  console.log(`[Stalwart] Updated hostname to "${domain}" in stalwart.toml`);
871
871
  } catch (err) {
872
872
  throw new Error(`Failed to set config server.hostname=${domain}`);
@@ -875,15 +875,15 @@ var StalwartAdmin = class {
875
875
  // --- DKIM ---
876
876
  /** Path to the host-side stalwart.toml (mounted read-only into container) */
877
877
  get configPath() {
878
- const { homedir: homedir8 } = __require("os");
879
- const { join: join9 } = __require("path");
880
- return join9(homedir8(), ".agenticmail", "stalwart.toml");
878
+ const { homedir: homedir9 } = __require("os");
879
+ const { join: join10 } = __require("path");
880
+ return join10(homedir9(), ".agenticmail", "stalwart.toml");
881
881
  }
882
882
  /** Path to host-side DKIM key directory */
883
883
  get dkimDir() {
884
- const { homedir: homedir8 } = __require("os");
885
- const { join: join9 } = __require("path");
886
- return join9(homedir8(), ".agenticmail");
884
+ const { homedir: homedir9 } = __require("os");
885
+ const { join: join10 } = __require("path");
886
+ return join10(homedir9(), ".agenticmail");
887
887
  }
888
888
  /**
889
889
  * Create/reuse a DKIM signing key for a domain.
@@ -984,12 +984,12 @@ var StalwartAdmin = class {
984
984
  * This bypasses the need for a PTR record on the sending IP.
985
985
  */
986
986
  async configureOutboundRelay(config) {
987
- const { readFileSync: readFileSync4, writeFileSync: writeFileSync5 } = await import("fs");
988
- const { homedir: homedir8 } = await import("os");
989
- const { join: join9 } = await import("path");
987
+ const { readFileSync: readFileSync5, writeFileSync: writeFileSync6 } = await import("fs");
988
+ const { homedir: homedir9 } = await import("os");
989
+ const { join: join10 } = await import("path");
990
990
  const routeName = config.routeName ?? "gmail";
991
- const tomlPath = join9(homedir8(), ".agenticmail", "stalwart.toml");
992
- let toml = readFileSync4(tomlPath, "utf-8");
991
+ const tomlPath = join10(homedir9(), ".agenticmail", "stalwart.toml");
992
+ let toml = readFileSync5(tomlPath, "utf-8");
993
993
  toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
994
994
  toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
995
995
  const safeRouteName = routeName.replace(/[^a-zA-Z0-9_-]/g, "");
@@ -1009,7 +1009,7 @@ auth.secret = "${escapeTomlString(config.password)}"
1009
1009
  route = [ { if = "is_local_domain('', rcpt_domain)", then = "'local'" },
1010
1010
  { else = "'${safeRouteName}'" } ]
1011
1011
  `;
1012
- writeFileSync5(tomlPath, toml, "utf-8");
1012
+ writeFileSync6(tomlPath, toml, "utf-8");
1013
1013
  await this.restartContainer();
1014
1014
  }
1015
1015
  };
@@ -5208,12 +5208,12 @@ var GatewayManager = class {
5208
5208
  zone = await this.cfClient.createZone(domain);
5209
5209
  }
5210
5210
  const existingRecords = await this.cfClient.listDnsRecords(zone.id);
5211
- const { homedir: homedir8 } = await import("os");
5212
- const backupDir = join4(homedir8(), ".agenticmail");
5211
+ const { homedir: homedir9 } = await import("os");
5212
+ const backupDir = join4(homedir9(), ".agenticmail");
5213
5213
  const backupPath = join4(backupDir, `dns-backup-${domain}-${Date.now()}.json`);
5214
- const { writeFileSync: writeFileSync5, mkdirSync: mkdirSync6 } = await import("fs");
5215
- mkdirSync6(backupDir, { recursive: true });
5216
- writeFileSync5(backupPath, JSON.stringify({
5214
+ const { writeFileSync: writeFileSync6, mkdirSync: mkdirSync7 } = await import("fs");
5215
+ mkdirSync7(backupDir, { recursive: true });
5216
+ writeFileSync6(backupPath, JSON.stringify({
5217
5217
  domain,
5218
5218
  zoneId: zone.id,
5219
5219
  backedUpAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -5901,17 +5901,122 @@ var RELAY_PRESETS = {
5901
5901
  }
5902
5902
  };
5903
5903
 
5904
+ // src/telemetry.ts
5905
+ import { randomUUID } from "crypto";
5906
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync3 } from "fs";
5907
+ import { join as join5 } from "path";
5908
+ import { homedir as homedir4 } from "os";
5909
+ import { platform as platform2 } from "process";
5910
+ var TELEMETRY_ENDPOINT = "https://agenticmail.io/api/telemetry";
5911
+ var BATCH_INTERVAL_MS = 6e4;
5912
+ var MAX_BATCH_SIZE = 100;
5913
+ var installId = null;
5914
+ var packageVersion = "unknown";
5915
+ var disabled = null;
5916
+ var batch = [];
5917
+ var flushTimer = null;
5918
+ var flushing = false;
5919
+ function isDisabled() {
5920
+ if (disabled !== null) return disabled;
5921
+ disabled = process.env.AGENTICMAIL_TELEMETRY === "0" || process.env.AGENTICMAIL_TELEMETRY === "false" || process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true" || process.env.CI === "true";
5922
+ return disabled;
5923
+ }
5924
+ function getInstallId() {
5925
+ if (installId) return installId;
5926
+ try {
5927
+ const dir = join5(homedir4(), ".agenticmail");
5928
+ const idFile = join5(dir, ".telemetry-id");
5929
+ if (existsSync3(idFile)) {
5930
+ const id = readFileSync2(idFile, "utf8").trim();
5931
+ if (id && id.length > 10) {
5932
+ installId = id;
5933
+ return installId;
5934
+ }
5935
+ }
5936
+ installId = randomUUID();
5937
+ if (!existsSync3(dir)) mkdirSync3(dir, { recursive: true });
5938
+ writeFileSync3(idFile, installId, "utf8");
5939
+ return installId;
5940
+ } catch {
5941
+ installId = randomUUID();
5942
+ return installId;
5943
+ }
5944
+ }
5945
+ function setTelemetryVersion(version) {
5946
+ packageVersion = version;
5947
+ }
5948
+ function recordToolCall(toolName) {
5949
+ try {
5950
+ if (isDisabled()) return;
5951
+ batch.push({ tool: toolName, ts: Date.now() });
5952
+ if (batch.length >= MAX_BATCH_SIZE) {
5953
+ flush();
5954
+ return;
5955
+ }
5956
+ if (!flushTimer) {
5957
+ flushTimer = setTimeout(() => {
5958
+ flushTimer = null;
5959
+ flush();
5960
+ }, BATCH_INTERVAL_MS);
5961
+ if (flushTimer && typeof flushTimer === "object" && "unref" in flushTimer) {
5962
+ flushTimer.unref();
5963
+ }
5964
+ }
5965
+ } catch {
5966
+ }
5967
+ }
5968
+ function flush() {
5969
+ if (flushing || batch.length === 0) return;
5970
+ flushing = true;
5971
+ const events = batch;
5972
+ batch = [];
5973
+ const toolCounts = {};
5974
+ for (const e of events) {
5975
+ toolCounts[e.tool] = (toolCounts[e.tool] || 0) + 1;
5976
+ }
5977
+ const payload = {
5978
+ id: getInstallId(),
5979
+ v: packageVersion,
5980
+ p: platform2,
5981
+ tools: toolCounts,
5982
+ n: events.length
5983
+ // total calls in this batch
5984
+ };
5985
+ fetch(TELEMETRY_ENDPOINT, {
5986
+ method: "POST",
5987
+ headers: { "Content-Type": "application/json" },
5988
+ body: JSON.stringify(payload),
5989
+ signal: AbortSignal.timeout(5e3)
5990
+ }).catch(() => {
5991
+ }).finally(() => {
5992
+ flushing = false;
5993
+ });
5994
+ }
5995
+ function flushTelemetry() {
5996
+ if (flushTimer) {
5997
+ clearTimeout(flushTimer);
5998
+ flushTimer = null;
5999
+ }
6000
+ flush();
6001
+ }
6002
+ try {
6003
+ process.on("beforeExit", flushTelemetry);
6004
+ process.on("SIGINT", flushTelemetry);
6005
+ process.on("SIGTERM", flushTelemetry);
6006
+ } catch {
6007
+ }
6008
+
5904
6009
  // src/setup/index.ts
5905
6010
  import { randomBytes as randomBytes3 } from "crypto";
5906
- import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, chmodSync as chmodSync2 } from "fs";
5907
- import { join as join8 } from "path";
5908
- import { homedir as homedir7 } from "os";
6011
+ import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, chmodSync as chmodSync2 } from "fs";
6012
+ import { join as join9 } from "path";
6013
+ import { homedir as homedir8 } from "os";
5909
6014
 
5910
6015
  // src/setup/deps.ts
5911
6016
  import { execFileSync } from "child_process";
5912
- import { existsSync as existsSync3 } from "fs";
5913
- import { join as join5 } from "path";
5914
- import { homedir as homedir4 } from "os";
6017
+ import { existsSync as existsSync4 } from "fs";
6018
+ import { join as join6 } from "path";
6019
+ import { homedir as homedir5 } from "os";
5915
6020
  var DependencyChecker = class {
5916
6021
  async checkAll() {
5917
6022
  return Promise.all([
@@ -5961,8 +6066,8 @@ var DependencyChecker = class {
5961
6066
  }
5962
6067
  }
5963
6068
  async checkCloudflared() {
5964
- const binPath = join5(homedir4(), ".agenticmail", "bin", "cloudflared");
5965
- if (existsSync3(binPath)) {
6069
+ const binPath = join6(homedir5(), ".agenticmail", "bin", "cloudflared");
6070
+ if (existsSync4(binPath)) {
5966
6071
  let version;
5967
6072
  try {
5968
6073
  const output = execFileSync(binPath, ["--version"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
@@ -5984,10 +6089,10 @@ var DependencyChecker = class {
5984
6089
 
5985
6090
  // src/setup/installer.ts
5986
6091
  import { execFileSync as execFileSync2, execSync, spawn as spawnChild } from "child_process";
5987
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, symlinkSync } from "fs";
6092
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, symlinkSync } from "fs";
5988
6093
  import { writeFile, rename, chmod as chmod2, mkdir as mkdir2, unlink } from "fs/promises";
5989
- import { join as join6 } from "path";
5990
- import { homedir as homedir5, platform as platform2, arch as arch2 } from "os";
6094
+ import { join as join7 } from "path";
6095
+ import { homedir as homedir6, platform as platform3, arch as arch2 } from "os";
5991
6096
  function runShellWithRollingOutput(cmd, opts = {}) {
5992
6097
  const maxLines = opts.maxLines ?? 20;
5993
6098
  const timeout = opts.timeout ?? 3e5;
@@ -6097,7 +6202,7 @@ var DependencyInstaller = class {
6097
6202
  */
6098
6203
  async installDocker() {
6099
6204
  if (this.isDockerReady()) return;
6100
- const os = platform2();
6205
+ const os = platform3();
6101
6206
  if (os === "darwin") {
6102
6207
  await this.installDockerMac();
6103
6208
  } else if (os === "linux") {
@@ -6163,11 +6268,11 @@ var DependencyInstaller = class {
6163
6268
  try {
6164
6269
  const composeBin = execFileSync2("which", ["docker-compose"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
6165
6270
  if (!composeBin) return;
6166
- const pluginDir = join6(homedir5(), ".docker", "cli-plugins");
6167
- const pluginPath = join6(pluginDir, "docker-compose");
6168
- if (existsSync4(pluginPath)) return;
6271
+ const pluginDir = join7(homedir6(), ".docker", "cli-plugins");
6272
+ const pluginPath = join7(pluginDir, "docker-compose");
6273
+ if (existsSync5(pluginPath)) return;
6169
6274
  try {
6170
- mkdirSync3(pluginDir, { recursive: true });
6275
+ mkdirSync4(pluginDir, { recursive: true });
6171
6276
  } catch {
6172
6277
  }
6173
6278
  try {
@@ -6230,9 +6335,9 @@ var DependencyInstaller = class {
6230
6335
  return;
6231
6336
  }
6232
6337
  this.onProgress("__progress__:5:Installing Docker Engine...");
6233
- const tmpDir = join6(homedir5(), ".agenticmail", "tmp");
6338
+ const tmpDir = join7(homedir6(), ".agenticmail", "tmp");
6234
6339
  await mkdir2(tmpDir, { recursive: true });
6235
- const scriptPath = join6(tmpDir, "install-docker.sh");
6340
+ const scriptPath = join7(tmpDir, "install-docker.sh");
6236
6341
  const dlResult = await runShellWithRollingOutput(
6237
6342
  `curl -fsSL https://get.docker.com -o "${scriptPath}" && sudo sh "${scriptPath}"`,
6238
6343
  { timeout: 3e5 }
@@ -6300,8 +6405,8 @@ var DependencyInstaller = class {
6300
6405
  }
6301
6406
  try {
6302
6407
  const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
6303
- const dockerExe = join6(programFiles, "Docker", "Docker", "Docker Desktop.exe");
6304
- if (existsSync4(dockerExe)) {
6408
+ const dockerExe = join7(programFiles, "Docker", "Docker", "Docker Desktop.exe");
6409
+ if (existsSync5(dockerExe)) {
6305
6410
  execSync(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
6306
6411
  }
6307
6412
  } catch {
@@ -6351,8 +6456,8 @@ var DependencyInstaller = class {
6351
6456
  this.onProgress("__progress__:70:Docker Desktop installed. Starting...");
6352
6457
  try {
6353
6458
  const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
6354
- const dockerExe = join6(programFiles, "Docker", "Docker", "Docker Desktop.exe");
6355
- if (existsSync4(dockerExe)) {
6459
+ const dockerExe = join7(programFiles, "Docker", "Docker", "Docker Desktop.exe");
6460
+ if (existsSync5(dockerExe)) {
6356
6461
  execSync(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
6357
6462
  }
6358
6463
  } catch {
@@ -6389,12 +6494,12 @@ var DependencyInstaller = class {
6389
6494
  * Start the Stalwart mail server Docker container.
6390
6495
  */
6391
6496
  async startStalwart(composePath) {
6392
- if (!existsSync4(composePath)) {
6497
+ if (!existsSync5(composePath)) {
6393
6498
  throw new Error(`docker-compose.yml not found at: ${composePath}`);
6394
6499
  }
6395
6500
  if (!this.isDockerReady()) {
6396
6501
  this.onProgress("Starting Docker...");
6397
- const os = platform2();
6502
+ const os = platform3();
6398
6503
  if (os === "darwin") {
6399
6504
  await this.startColima();
6400
6505
  } else if (os === "win32") {
@@ -6412,7 +6517,7 @@ var DependencyInstaller = class {
6412
6517
  }
6413
6518
  }
6414
6519
  this.onProgress("__progress__:10:Pulling mail server image...");
6415
- if (platform2() === "darwin") this.linkComposePlugin();
6520
+ if (platform3() === "darwin") this.linkComposePlugin();
6416
6521
  let composeResult = await runSilent("docker", ["compose", "-f", composePath, "up", "-d"], { timeout: 12e4 });
6417
6522
  if (composeResult.exitCode !== 0 && hasCommand("docker-compose")) {
6418
6523
  composeResult = await runSilent("docker-compose", ["-f", composePath, "up", "-d"], { timeout: 12e4 });
@@ -6447,17 +6552,17 @@ var DependencyInstaller = class {
6447
6552
  * Returns the path to the installed binary.
6448
6553
  */
6449
6554
  async installCloudflared() {
6450
- const os = platform2();
6451
- const binDir = join6(homedir5(), ".agenticmail", "bin");
6555
+ const os = platform3();
6556
+ const binDir = join7(homedir6(), ".agenticmail", "bin");
6452
6557
  const binName = os === "win32" ? "cloudflared.exe" : "cloudflared";
6453
- const binPath = join6(binDir, binName);
6454
- if (existsSync4(binPath)) {
6558
+ const binPath = join7(binDir, binName);
6559
+ if (existsSync5(binPath)) {
6455
6560
  return binPath;
6456
6561
  }
6457
6562
  try {
6458
6563
  const whichCmd = os === "win32" ? "where" : "which";
6459
6564
  const sysPath = execFileSync2(whichCmd, ["cloudflared"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim().split("\n")[0];
6460
- if (sysPath && existsSync4(sysPath)) return sysPath;
6565
+ if (sysPath && existsSync5(sysPath)) return sysPath;
6461
6566
  } catch {
6462
6567
  }
6463
6568
  this.onProgress("Downloading cloudflared...");
@@ -6480,7 +6585,7 @@ var DependencyInstaller = class {
6480
6585
  }
6481
6586
  const buffer = Buffer.from(await response.arrayBuffer());
6482
6587
  if (os === "darwin") {
6483
- const tgzPath = join6(binDir, "cloudflared.tgz");
6588
+ const tgzPath = join7(binDir, "cloudflared.tgz");
6484
6589
  await writeFile(tgzPath, buffer);
6485
6590
  try {
6486
6591
  execFileSync2("tar", ["-xzf", tgzPath, "-C", binDir, "cloudflared"], { timeout: 15e3, stdio: "ignore" });
@@ -6497,7 +6602,7 @@ var DependencyInstaller = class {
6497
6602
  if (os !== "win32") await chmod2(tmpPath, 493);
6498
6603
  await rename(tmpPath, binPath);
6499
6604
  }
6500
- if (!existsSync4(binPath)) {
6605
+ if (!existsSync5(binPath)) {
6501
6606
  throw new Error("cloudflared download succeeded but binary not found after extraction");
6502
6607
  }
6503
6608
  this.onProgress("cloudflared installed");
@@ -6515,21 +6620,21 @@ var DependencyInstaller = class {
6515
6620
 
6516
6621
  // src/setup/service.ts
6517
6622
  import { execFileSync as execFileSync3, execSync as execSync2 } from "child_process";
6518
- import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as mkdirSync4, chmodSync } from "fs";
6519
- import { join as join7 } from "path";
6520
- import { homedir as homedir6, platform as platform3 } from "os";
6623
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync5, chmodSync } from "fs";
6624
+ import { join as join8 } from "path";
6625
+ import { homedir as homedir7, platform as platform4 } from "os";
6521
6626
  var PLIST_LABEL = "com.agenticmail.server";
6522
6627
  var SYSTEMD_UNIT = "agenticmail.service";
6523
6628
  var ServiceManager = class {
6524
- os = platform3();
6629
+ os = platform4();
6525
6630
  /**
6526
6631
  * Get the path to the service file.
6527
6632
  */
6528
6633
  getServicePath() {
6529
6634
  if (this.os === "darwin") {
6530
- return join7(homedir6(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
6635
+ return join8(homedir7(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
6531
6636
  } else {
6532
- return join7(homedir6(), ".config", "systemd", "user", SYSTEMD_UNIT);
6637
+ return join8(homedir7(), ".config", "systemd", "user", SYSTEMD_UNIT);
6533
6638
  }
6534
6639
  }
6535
6640
  /**
@@ -6549,14 +6654,14 @@ var ServiceManager = class {
6549
6654
  getApiEntryPath() {
6550
6655
  const searchDirs = [
6551
6656
  // Global npm install
6552
- join7(homedir6(), "node_modules", "agenticmail"),
6657
+ join8(homedir7(), "node_modules", "agenticmail"),
6553
6658
  // npx cache / global prefix
6554
6659
  ...(() => {
6555
6660
  try {
6556
6661
  const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
6557
6662
  return [
6558
- join7(prefix, "lib", "node_modules", "agenticmail"),
6559
- join7(prefix, "node_modules", "agenticmail")
6663
+ join8(prefix, "lib", "node_modules", "agenticmail"),
6664
+ join8(prefix, "node_modules", "agenticmail")
6560
6665
  ];
6561
6666
  } catch {
6562
6667
  return [];
@@ -6568,18 +6673,18 @@ var ServiceManager = class {
6568
6673
  ];
6569
6674
  for (const base of searchDirs) {
6570
6675
  const apiPaths = [
6571
- join7(base, "node_modules", "@agenticmail", "api", "dist", "index.js"),
6572
- join7(base, "..", "@agenticmail", "api", "dist", "index.js")
6676
+ join8(base, "node_modules", "@agenticmail", "api", "dist", "index.js"),
6677
+ join8(base, "..", "@agenticmail", "api", "dist", "index.js")
6573
6678
  ];
6574
6679
  for (const p of apiPaths) {
6575
- if (existsSync5(p)) return p;
6680
+ if (existsSync6(p)) return p;
6576
6681
  }
6577
6682
  }
6578
- const dataDir = join7(homedir6(), ".agenticmail");
6579
- const entryCache = join7(dataDir, "api-entry.path");
6580
- if (existsSync5(entryCache)) {
6581
- const cached = readFileSync2(entryCache, "utf-8").trim();
6582
- if (existsSync5(cached)) return cached;
6683
+ const dataDir = join8(homedir7(), ".agenticmail");
6684
+ const entryCache = join8(dataDir, "api-entry.path");
6685
+ if (existsSync6(entryCache)) {
6686
+ const cached = readFileSync3(entryCache, "utf-8").trim();
6687
+ if (existsSync6(cached)) return cached;
6583
6688
  }
6584
6689
  throw new Error("Could not find @agenticmail/api entry point. Run `agenticmail start` first to populate the cache.");
6585
6690
  }
@@ -6587,9 +6692,9 @@ var ServiceManager = class {
6587
6692
  * Cache the API entry path so the service can find it later.
6588
6693
  */
6589
6694
  cacheApiEntryPath(entryPath) {
6590
- const dataDir = join7(homedir6(), ".agenticmail");
6591
- if (!existsSync5(dataDir)) mkdirSync4(dataDir, { recursive: true });
6592
- writeFileSync3(join7(dataDir, "api-entry.path"), entryPath);
6695
+ const dataDir = join8(homedir7(), ".agenticmail");
6696
+ if (!existsSync6(dataDir)) mkdirSync5(dataDir, { recursive: true });
6697
+ writeFileSync4(join8(dataDir, "api-entry.path"), entryPath);
6593
6698
  }
6594
6699
  /**
6595
6700
  * Get the current package version.
@@ -6597,17 +6702,17 @@ var ServiceManager = class {
6597
6702
  getVersion() {
6598
6703
  try {
6599
6704
  const pkgPaths = [
6600
- join7(homedir6(), "node_modules", "agenticmail", "package.json"),
6601
- join7(homedir6(), ".agenticmail", "package-version.json")
6705
+ join8(homedir7(), "node_modules", "agenticmail", "package.json"),
6706
+ join8(homedir7(), ".agenticmail", "package-version.json")
6602
6707
  ];
6603
6708
  try {
6604
6709
  const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
6605
- pkgPaths.push(join7(prefix, "lib", "node_modules", "agenticmail", "package.json"));
6710
+ pkgPaths.push(join8(prefix, "lib", "node_modules", "agenticmail", "package.json"));
6606
6711
  } catch {
6607
6712
  }
6608
6713
  for (const p of pkgPaths) {
6609
- if (existsSync5(p)) {
6610
- const pkg = JSON.parse(readFileSync2(p, "utf-8"));
6714
+ if (existsSync6(p)) {
6715
+ const pkg = JSON.parse(readFileSync3(p, "utf-8"));
6611
6716
  if (pkg.version) return pkg.version;
6612
6717
  }
6613
6718
  }
@@ -6620,9 +6725,9 @@ var ServiceManager = class {
6620
6725
  * This ensures AgenticMail doesn't fail on boot when Docker is still loading.
6621
6726
  */
6622
6727
  generateStartScript(nodePath, apiEntry) {
6623
- const scriptPath = join7(homedir6(), ".agenticmail", "bin", "start-server.sh");
6624
- const scriptDir = join7(homedir6(), ".agenticmail", "bin");
6625
- if (!existsSync5(scriptDir)) mkdirSync4(scriptDir, { recursive: true });
6728
+ const scriptPath = join8(homedir7(), ".agenticmail", "bin", "start-server.sh");
6729
+ const scriptDir = join8(homedir7(), ".agenticmail", "bin");
6730
+ if (!existsSync6(scriptDir)) mkdirSync5(scriptDir, { recursive: true });
6626
6731
  const script = [
6627
6732
  "#!/bin/bash",
6628
6733
  "# AgenticMail auto-start script",
@@ -6673,7 +6778,7 @@ var ServiceManager = class {
6673
6778
  `log "Starting API server: ${nodePath} ${apiEntry}"`,
6674
6779
  `exec "${nodePath}" "${apiEntry}"`
6675
6780
  ].join("\n") + "\n";
6676
- writeFileSync3(scriptPath, script, { mode: 493 });
6781
+ writeFileSync4(scriptPath, script, { mode: 493 });
6677
6782
  return scriptPath;
6678
6783
  }
6679
6784
  /**
@@ -6686,9 +6791,9 @@ var ServiceManager = class {
6686
6791
  * - Service version tracking in env vars
6687
6792
  */
6688
6793
  generatePlist(nodePath, apiEntry, configPath) {
6689
- const config = JSON.parse(readFileSync2(configPath, "utf-8"));
6690
- const logDir = join7(homedir6(), ".agenticmail", "logs");
6691
- if (!existsSync5(logDir)) mkdirSync4(logDir, { recursive: true });
6794
+ const config = JSON.parse(readFileSync3(configPath, "utf-8"));
6795
+ const logDir = join8(homedir7(), ".agenticmail", "logs");
6796
+ if (!existsSync6(logDir)) mkdirSync5(logDir, { recursive: true });
6692
6797
  const version = this.getVersion();
6693
6798
  const startScript = this.generateStartScript(nodePath, apiEntry);
6694
6799
  return `<?xml version="1.0" encoding="UTF-8"?>
@@ -6709,9 +6814,9 @@ var ServiceManager = class {
6709
6814
  <key>EnvironmentVariables</key>
6710
6815
  <dict>
6711
6816
  <key>HOME</key>
6712
- <string>${homedir6()}</string>
6817
+ <string>${homedir7()}</string>
6713
6818
  <key>AGENTICMAIL_DATA_DIR</key>
6714
- <string>${config.dataDir || join7(homedir6(), ".agenticmail")}</string>
6819
+ <string>${config.dataDir || join8(homedir7(), ".agenticmail")}</string>
6715
6820
  <key>PATH</key>
6716
6821
  <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
6717
6822
  <key>AGENTICMAIL_SERVICE_VERSION</key>
@@ -6764,8 +6869,8 @@ var ServiceManager = class {
6764
6869
  * - Proper dependency ordering
6765
6870
  */
6766
6871
  generateSystemdUnit(nodePath, apiEntry, configPath) {
6767
- const config = JSON.parse(readFileSync2(configPath, "utf-8"));
6768
- const dataDir = config.dataDir || join7(homedir6(), ".agenticmail");
6872
+ const config = JSON.parse(readFileSync3(configPath, "utf-8"));
6873
+ const dataDir = config.dataDir || join8(homedir7(), ".agenticmail");
6769
6874
  const version = this.getVersion();
6770
6875
  const startScript = this.generateStartScript(nodePath, apiEntry);
6771
6876
  return `[Unit]
@@ -6782,7 +6887,7 @@ Restart=always
6782
6887
  RestartSec=15
6783
6888
  TimeoutStartSec=660
6784
6889
  LimitNOFILE=8192
6785
- Environment=HOME=${homedir6()}
6890
+ Environment=HOME=${homedir7()}
6786
6891
  Environment=AGENTICMAIL_DATA_DIR=${dataDir}
6787
6892
  Environment=PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin
6788
6893
  Environment=AGENTICMAIL_SERVICE_VERSION=${version}
@@ -6795,8 +6900,8 @@ WantedBy=default.target
6795
6900
  * Install the auto-start service.
6796
6901
  */
6797
6902
  install() {
6798
- const configPath = join7(homedir6(), ".agenticmail", "config.json");
6799
- if (!existsSync5(configPath)) {
6903
+ const configPath = join8(homedir7(), ".agenticmail", "config.json");
6904
+ if (!existsSync6(configPath)) {
6800
6905
  return { installed: false, message: "Config not found. Run agenticmail setup first." };
6801
6906
  }
6802
6907
  const nodePath = this.getNodePath();
@@ -6808,16 +6913,16 @@ WantedBy=default.target
6808
6913
  }
6809
6914
  const servicePath = this.getServicePath();
6810
6915
  if (this.os === "darwin") {
6811
- const dir = join7(homedir6(), "Library", "LaunchAgents");
6812
- if (!existsSync5(dir)) mkdirSync4(dir, { recursive: true });
6813
- if (existsSync5(servicePath)) {
6916
+ const dir = join8(homedir7(), "Library", "LaunchAgents");
6917
+ if (!existsSync6(dir)) mkdirSync5(dir, { recursive: true });
6918
+ if (existsSync6(servicePath)) {
6814
6919
  try {
6815
6920
  execFileSync3("launchctl", ["unload", servicePath], { timeout: 1e4, stdio: "ignore" });
6816
6921
  } catch {
6817
6922
  }
6818
6923
  }
6819
6924
  const plist = this.generatePlist(nodePath, apiEntry, configPath);
6820
- writeFileSync3(servicePath, plist);
6925
+ writeFileSync4(servicePath, plist);
6821
6926
  chmodSync(servicePath, 384);
6822
6927
  try {
6823
6928
  execFileSync3("launchctl", ["load", servicePath], { timeout: 1e4, stdio: "ignore" });
@@ -6826,10 +6931,10 @@ WantedBy=default.target
6826
6931
  }
6827
6932
  return { installed: true, message: `Service installed at ${servicePath}` };
6828
6933
  } else if (this.os === "linux") {
6829
- const dir = join7(homedir6(), ".config", "systemd", "user");
6830
- if (!existsSync5(dir)) mkdirSync4(dir, { recursive: true });
6934
+ const dir = join8(homedir7(), ".config", "systemd", "user");
6935
+ if (!existsSync6(dir)) mkdirSync5(dir, { recursive: true });
6831
6936
  const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
6832
- writeFileSync3(servicePath, unit);
6937
+ writeFileSync4(servicePath, unit);
6833
6938
  chmodSync(servicePath, 384);
6834
6939
  try {
6835
6940
  execFileSync3("systemctl", ["--user", "daemon-reload"], { timeout: 1e4, stdio: "ignore" });
@@ -6852,7 +6957,7 @@ WantedBy=default.target
6852
6957
  */
6853
6958
  uninstall() {
6854
6959
  const servicePath = this.getServicePath();
6855
- if (!existsSync5(servicePath)) {
6960
+ if (!existsSync6(servicePath)) {
6856
6961
  return { removed: false, message: "Service is not installed." };
6857
6962
  }
6858
6963
  if (this.os === "darwin") {
@@ -6890,7 +6995,7 @@ WantedBy=default.target
6890
6995
  status() {
6891
6996
  const servicePath = this.getServicePath();
6892
6997
  const plat = this.os === "darwin" ? "launchd" : this.os === "linux" ? "systemd" : "unsupported";
6893
- const installed = existsSync5(servicePath);
6998
+ const installed = existsSync6(servicePath);
6894
6999
  let running = false;
6895
7000
  if (installed) {
6896
7001
  if (this.os === "darwin") {
@@ -6960,13 +7065,13 @@ var SetupManager = class {
6960
7065
  * falls back to monorepo location.
6961
7066
  */
6962
7067
  getComposePath() {
6963
- const standalonePath = join8(homedir7(), ".agenticmail", "docker-compose.yml");
6964
- if (existsSync6(standalonePath)) return standalonePath;
7068
+ const standalonePath = join9(homedir8(), ".agenticmail", "docker-compose.yml");
7069
+ if (existsSync7(standalonePath)) return standalonePath;
6965
7070
  const cwd = process.cwd();
6966
- const candidates = [cwd, join8(cwd, "..")];
7071
+ const candidates = [cwd, join9(cwd, "..")];
6967
7072
  for (const dir of candidates) {
6968
- const p = join8(dir, "docker-compose.yml");
6969
- if (existsSync6(p)) return p;
7073
+ const p = join9(dir, "docker-compose.yml");
7074
+ if (existsSync7(p)) return p;
6970
7075
  }
6971
7076
  return standalonePath;
6972
7077
  }
@@ -6976,19 +7081,19 @@ var SetupManager = class {
6976
7081
  * Always regenerates Docker files to keep passwords in sync.
6977
7082
  */
6978
7083
  initConfig() {
6979
- const dataDir = join8(homedir7(), ".agenticmail");
6980
- const configPath = join8(dataDir, "config.json");
6981
- const envPath = join8(dataDir, ".env");
6982
- if (existsSync6(configPath)) {
7084
+ const dataDir = join9(homedir8(), ".agenticmail");
7085
+ const configPath = join9(dataDir, "config.json");
7086
+ const envPath = join9(dataDir, ".env");
7087
+ if (existsSync7(configPath)) {
6983
7088
  try {
6984
- const existing = JSON.parse(readFileSync3(configPath, "utf-8"));
7089
+ const existing = JSON.parse(readFileSync4(configPath, "utf-8"));
6985
7090
  this.generateDockerFiles(existing);
6986
7091
  return { configPath, envPath, config: existing, isNew: false };
6987
7092
  } catch {
6988
7093
  }
6989
7094
  }
6990
- if (!existsSync6(dataDir)) {
6991
- mkdirSync5(dataDir, { recursive: true });
7095
+ if (!existsSync7(dataDir)) {
7096
+ mkdirSync6(dataDir, { recursive: true });
6992
7097
  }
6993
7098
  const masterKey = `mk_${randomBytes3(24).toString("hex")}`;
6994
7099
  const stalwartPassword = randomBytes3(16).toString("hex");
@@ -7004,7 +7109,7 @@ var SetupManager = class {
7004
7109
  api: { port: 3100, host: "127.0.0.1" },
7005
7110
  dataDir
7006
7111
  };
7007
- writeFileSync4(configPath, JSON.stringify(config, null, 2));
7112
+ writeFileSync5(configPath, JSON.stringify(config, null, 2));
7008
7113
  chmodSync2(configPath, 384);
7009
7114
  const envContent = `# Auto-generated by agenticmail setup
7010
7115
  STALWART_ADMIN_USER=admin
@@ -7020,7 +7125,7 @@ SMTP_PORT=587
7020
7125
  IMAP_HOST=localhost
7021
7126
  IMAP_PORT=143
7022
7127
  `;
7023
- writeFileSync4(envPath, envContent);
7128
+ writeFileSync5(envPath, envContent);
7024
7129
  chmodSync2(envPath, 384);
7025
7130
  this.generateDockerFiles(config);
7026
7131
  return { configPath, envPath, config, isNew: true };
@@ -7030,13 +7135,13 @@ IMAP_PORT=143
7030
7135
  * with the correct admin password from config.
7031
7136
  */
7032
7137
  generateDockerFiles(config) {
7033
- const dataDir = config.dataDir || join8(homedir7(), ".agenticmail");
7034
- if (!existsSync6(dataDir)) {
7035
- mkdirSync5(dataDir, { recursive: true });
7138
+ const dataDir = config.dataDir || join9(homedir8(), ".agenticmail");
7139
+ if (!existsSync7(dataDir)) {
7140
+ mkdirSync6(dataDir, { recursive: true });
7036
7141
  }
7037
7142
  const password = config.stalwart?.adminPassword || "changeme";
7038
- const composePath = join8(dataDir, "docker-compose.yml");
7039
- writeFileSync4(composePath, `services:
7143
+ const composePath = join9(dataDir, "docker-compose.yml");
7144
+ writeFileSync5(composePath, `services:
7040
7145
  stalwart:
7041
7146
  image: stalwartlabs/stalwart:latest
7042
7147
  container_name: agenticmail-stalwart
@@ -7059,8 +7164,8 @@ volumes:
7059
7164
  stalwart-data:
7060
7165
  `);
7061
7166
  chmodSync2(composePath, 384);
7062
- const tomlPath = join8(dataDir, "stalwart.toml");
7063
- writeFileSync4(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
7167
+ const tomlPath = join9(dataDir, "stalwart.toml");
7168
+ writeFileSync5(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
7064
7169
 
7065
7170
  [server]
7066
7171
  hostname = "localhost"
@@ -7116,8 +7221,8 @@ secret = "${password}"
7116
7221
  * Check if config has already been initialized.
7117
7222
  */
7118
7223
  isInitialized() {
7119
- const configPath = join8(homedir7(), ".agenticmail", "config.json");
7120
- return existsSync6(configPath);
7224
+ const configPath = join9(homedir8(), ".agenticmail", "config.json");
7225
+ return existsSync7(configPath);
7121
7226
  }
7122
7227
  };
7123
7228
  export {
@@ -7156,16 +7261,19 @@ export {
7156
7261
  debugWarn,
7157
7262
  ensureDataDir,
7158
7263
  extractVerificationCode,
7264
+ flushTelemetry,
7159
7265
  getDatabase,
7160
7266
  isInternalEmail,
7161
7267
  isValidPhoneNumber,
7162
7268
  normalizePhoneNumber,
7163
7269
  parseEmail,
7164
7270
  parseGoogleVoiceSms,
7271
+ recordToolCall,
7165
7272
  resolveConfig,
7166
7273
  sanitizeEmail,
7167
7274
  saveConfig,
7168
7275
  scanOutboundEmail,
7169
7276
  scoreEmail,
7277
+ setTelemetryVersion,
7170
7278
  startRelayBridge
7171
7279
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/core",
3
- "version": "0.5.38",
3
+ "version": "0.5.40",
4
4
  "description": "Core SDK for AgenticMail — email, SMS, and phone number access for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",