@agenticmail/core 0.5.0 → 0.5.2

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
@@ -1450,6 +1450,92 @@ declare class DependencyInstaller {
1450
1450
  installAll(composePath: string): Promise<void>;
1451
1451
  }
1452
1452
 
1453
+ interface ServiceStatus {
1454
+ installed: boolean;
1455
+ running: boolean;
1456
+ platform: 'launchd' | 'systemd' | 'unsupported';
1457
+ servicePath: string | null;
1458
+ }
1459
+ /**
1460
+ * ServiceManager handles auto-start on boot for the AgenticMail API server.
1461
+ * - macOS: LaunchAgent plist (user-level, no sudo needed)
1462
+ * - Linux: systemd user service (user-level, no sudo needed)
1463
+ */
1464
+ declare class ServiceManager {
1465
+ private os;
1466
+ /**
1467
+ * Get the path to the service file.
1468
+ */
1469
+ private getServicePath;
1470
+ /**
1471
+ * Find the Node.js binary path.
1472
+ */
1473
+ private getNodePath;
1474
+ /**
1475
+ * Find the API server entry point.
1476
+ * Searches common locations where agenticmail is installed.
1477
+ */
1478
+ private getApiEntryPath;
1479
+ /**
1480
+ * Cache the API entry path so the service can find it later.
1481
+ */
1482
+ cacheApiEntryPath(entryPath: string): void;
1483
+ /**
1484
+ * Get the current package version.
1485
+ */
1486
+ private getVersion;
1487
+ /**
1488
+ * Generate a wrapper script that waits for Docker before starting the API.
1489
+ * This ensures AgenticMail doesn't fail on boot when Docker is still loading.
1490
+ */
1491
+ private generateStartScript;
1492
+ /**
1493
+ * Generate the launchd plist content for macOS.
1494
+ * More robust than OpenClaw's plist:
1495
+ * - Wrapper script waits for Docker + Stalwart before starting
1496
+ * - KeepAlive: true (unconditional — always restart, not just on crash)
1497
+ * - SoftResourceLimits for file descriptors (email servers need many)
1498
+ * - StartInterval as backup heartbeat (checks every 5 min)
1499
+ * - Service version tracking in env vars
1500
+ */
1501
+ private generatePlist;
1502
+ /**
1503
+ * Generate the systemd user service content for Linux.
1504
+ * More robust than basic services:
1505
+ * - Wrapper script waits for Docker + Stalwart
1506
+ * - Restart=always (unconditional)
1507
+ * - WatchdogSec for health monitoring
1508
+ * - File descriptor limits
1509
+ * - Proper dependency ordering
1510
+ */
1511
+ private generateSystemdUnit;
1512
+ /**
1513
+ * Install the auto-start service.
1514
+ */
1515
+ install(): {
1516
+ installed: boolean;
1517
+ message: string;
1518
+ };
1519
+ /**
1520
+ * Uninstall the auto-start service.
1521
+ */
1522
+ uninstall(): {
1523
+ removed: boolean;
1524
+ message: string;
1525
+ };
1526
+ /**
1527
+ * Get the current service status.
1528
+ */
1529
+ status(): ServiceStatus;
1530
+ /**
1531
+ * Reinstall the service (useful after config changes or updates).
1532
+ */
1533
+ reinstall(): {
1534
+ installed: boolean;
1535
+ message: string;
1536
+ };
1537
+ }
1538
+
1453
1539
  interface SetupConfig {
1454
1540
  masterKey: string;
1455
1541
  stalwart: {
@@ -1524,4 +1610,4 @@ declare class SetupManager {
1524
1610
  isInitialized(): boolean;
1525
1611
  }
1526
1612
 
1527
- 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, 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 };
1613
+ 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 };
package/dist/index.js CHANGED
@@ -818,10 +818,10 @@ var StalwartAdmin = class {
818
818
  return ["exec", "agenticmail-stalwart", "stalwart-cli", "-u", "http://localhost:8080", "-c", creds];
819
819
  }
820
820
  async updateSetting(key, value) {
821
- const { execFileSync: execFileSync3 } = await import("child_process");
821
+ const { execFileSync: execFileSync4 } = await import("child_process");
822
822
  const cli = this.cliArgs();
823
823
  try {
824
- execFileSync3(
824
+ execFileSync4(
825
825
  "docker",
826
826
  [...cli, "server", "delete-config", key],
827
827
  { timeout: 15e3, stdio: ["ignore", "pipe", "pipe"] }
@@ -829,13 +829,13 @@ var StalwartAdmin = class {
829
829
  } catch {
830
830
  }
831
831
  try {
832
- execFileSync3(
832
+ execFileSync4(
833
833
  "docker",
834
834
  [...cli, "server", "add-config", key, value],
835
835
  { timeout: 15e3, stdio: ["ignore", "pipe", "pipe"] }
836
836
  );
837
837
  } catch {
838
- const output = execFileSync3(
838
+ const output = execFileSync4(
839
839
  "docker",
840
840
  [...cli, "server", "list-config", key],
841
841
  { timeout: 15e3, stdio: ["ignore", "pipe", "pipe"] }
@@ -850,14 +850,14 @@ var StalwartAdmin = class {
850
850
  * Critical for email deliverability — must match the sending domain.
851
851
  */
852
852
  async setHostname(domain) {
853
- const { readFileSync: readFileSync3, writeFileSync: writeFileSync4 } = await import("fs");
854
- const { homedir: homedir7 } = await import("os");
855
- const { join: join8 } = await import("path");
856
- const configPath = join8(homedir7(), ".agenticmail", "stalwart.toml");
853
+ const { readFileSync: readFileSync4, writeFileSync: writeFileSync5 } = await import("fs");
854
+ const { homedir: homedir8 } = await import("os");
855
+ const { join: join9 } = await import("path");
856
+ const configPath = join9(homedir8(), ".agenticmail", "stalwart.toml");
857
857
  try {
858
- let config = readFileSync3(configPath, "utf-8");
858
+ let config = readFileSync4(configPath, "utf-8");
859
859
  config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${domain}"`);
860
- writeFileSync4(configPath, config);
860
+ writeFileSync5(configPath, config);
861
861
  console.log(`[Stalwart] Updated hostname to "${domain}" in stalwart.toml`);
862
862
  } catch (err) {
863
863
  throw new Error(`Failed to set config server.hostname=${domain}`);
@@ -866,15 +866,15 @@ var StalwartAdmin = class {
866
866
  // --- DKIM ---
867
867
  /** Path to the host-side stalwart.toml (mounted read-only into container) */
868
868
  get configPath() {
869
- const { homedir: homedir7 } = __require("os");
870
- const { join: join8 } = __require("path");
871
- return join8(homedir7(), ".agenticmail", "stalwart.toml");
869
+ const { homedir: homedir8 } = __require("os");
870
+ const { join: join9 } = __require("path");
871
+ return join9(homedir8(), ".agenticmail", "stalwart.toml");
872
872
  }
873
873
  /** Path to host-side DKIM key directory */
874
874
  get dkimDir() {
875
- const { homedir: homedir7 } = __require("os");
876
- const { join: join8 } = __require("path");
877
- return join8(homedir7(), ".agenticmail");
875
+ const { homedir: homedir8 } = __require("os");
876
+ const { join: join9 } = __require("path");
877
+ return join9(homedir8(), ".agenticmail");
878
878
  }
879
879
  /**
880
880
  * Create/reuse a DKIM signing key for a domain.
@@ -882,7 +882,7 @@ var StalwartAdmin = class {
882
882
  * Returns the public key (base64, no headers) for DNS TXT record.
883
883
  */
884
884
  async createDkimSignature(domain, selector = "agenticmail") {
885
- const { execFileSync: execFileSync3 } = await import("child_process");
885
+ const { execFileSync: execFileSync4 } = await import("child_process");
886
886
  const signatureId = `agenticmail-${domain.replace(/\./g, "-")}`;
887
887
  const cli = this.cliArgs();
888
888
  const existing = await this.getSettings(`signature.${signatureId}`);
@@ -890,7 +890,7 @@ var StalwartAdmin = class {
890
890
  console.log(`[DKIM] Reusing existing signature "${signatureId}" from Stalwart DB`);
891
891
  } else {
892
892
  try {
893
- execFileSync3("docker", [...cli, "server", "delete-config", `signature.${signatureId}`], {
893
+ execFileSync4("docker", [...cli, "server", "delete-config", `signature.${signatureId}`], {
894
894
  timeout: 1e4,
895
895
  stdio: ["ignore", "pipe", "pipe"]
896
896
  });
@@ -898,7 +898,7 @@ var StalwartAdmin = class {
898
898
  }
899
899
  console.log(`[DKIM] Creating RSA signature for ${domain} via stalwart-cli`);
900
900
  try {
901
- execFileSync3("docker", [...cli, "dkim", "create", "rsa", domain, signatureId, selector], {
901
+ execFileSync4("docker", [...cli, "dkim", "create", "rsa", domain, signatureId, selector], {
902
902
  timeout: 15e3,
903
903
  stdio: ["ignore", "pipe", "pipe"]
904
904
  });
@@ -915,7 +915,7 @@ var StalwartAdmin = class {
915
915
  ["auth.dkim.sign.0001.else", "false"]
916
916
  ];
917
917
  for (const [key, value] of rules) {
918
- execFileSync3("docker", [...cli, "server", "add-config", key, value], {
918
+ execFileSync4("docker", [...cli, "server", "add-config", key, value], {
919
919
  timeout: 1e4,
920
920
  stdio: ["ignore", "pipe", "pipe"]
921
921
  });
@@ -923,7 +923,7 @@ var StalwartAdmin = class {
923
923
  }
924
924
  let publicKey;
925
925
  try {
926
- const output = execFileSync3("docker", [...cli, "dkim", "get-public-key", signatureId], {
926
+ const output = execFileSync4("docker", [...cli, "dkim", "get-public-key", signatureId], {
927
927
  timeout: 1e4,
928
928
  stdio: ["ignore", "pipe", "pipe"]
929
929
  }).toString();
@@ -934,7 +934,7 @@ var StalwartAdmin = class {
934
934
  throw new Error(`Failed to get DKIM public key: ${err.message}`);
935
935
  }
936
936
  try {
937
- execFileSync3("docker", [...cli, "server", "reload-config"], {
937
+ execFileSync4("docker", [...cli, "server", "reload-config"], {
938
938
  timeout: 1e4,
939
939
  stdio: ["ignore", "pipe", "pipe"]
940
940
  });
@@ -947,9 +947,9 @@ var StalwartAdmin = class {
947
947
  * Restart the Stalwart Docker container and wait for it to be ready.
948
948
  */
949
949
  async restartContainer() {
950
- const { execFileSync: execFileSync3 } = await import("child_process");
950
+ const { execFileSync: execFileSync4 } = await import("child_process");
951
951
  try {
952
- execFileSync3("docker", ["restart", "agenticmail-stalwart"], { timeout: 3e4, stdio: ["ignore", "pipe", "pipe"] });
952
+ execFileSync4("docker", ["restart", "agenticmail-stalwart"], { timeout: 3e4, stdio: ["ignore", "pipe", "pipe"] });
953
953
  for (let i = 0; i < 15; i++) {
954
954
  try {
955
955
  const res = await fetch(`${this.baseUrl}/health`, { signal: AbortSignal.timeout(2e3) });
@@ -975,12 +975,12 @@ var StalwartAdmin = class {
975
975
  * This bypasses the need for a PTR record on the sending IP.
976
976
  */
977
977
  async configureOutboundRelay(config) {
978
- const { readFileSync: readFileSync3, writeFileSync: writeFileSync4 } = await import("fs");
979
- const { homedir: homedir7 } = await import("os");
980
- const { join: join8 } = await import("path");
978
+ const { readFileSync: readFileSync4, writeFileSync: writeFileSync5 } = await import("fs");
979
+ const { homedir: homedir8 } = await import("os");
980
+ const { join: join9 } = await import("path");
981
981
  const routeName = config.routeName ?? "gmail";
982
- const tomlPath = join8(homedir7(), ".agenticmail", "stalwart.toml");
983
- let toml = readFileSync3(tomlPath, "utf-8");
982
+ const tomlPath = join9(homedir8(), ".agenticmail", "stalwart.toml");
983
+ let toml = readFileSync4(tomlPath, "utf-8");
984
984
  toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
985
985
  toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
986
986
  toml += `
@@ -999,7 +999,7 @@ auth.secret = "${config.password}"
999
999
  route = [ { if = "is_local_domain('', rcpt_domain)", then = "'local'" },
1000
1000
  { else = "'${routeName}'" } ]
1001
1001
  `;
1002
- writeFileSync4(tomlPath, toml, "utf-8");
1002
+ writeFileSync5(tomlPath, toml, "utf-8");
1003
1003
  await this.restartContainer();
1004
1004
  }
1005
1005
  };
@@ -3819,8 +3819,8 @@ var CloudflareClient = class {
3819
3819
  let available = false;
3820
3820
  if (result.supported_tld && !hasRegistration) {
3821
3821
  try {
3822
- const { execFileSync: execFileSync3 } = await import("child_process");
3823
- const whoisOutput = execFileSync3("whois", [domain], { timeout: 1e4, stdio: ["ignore", "pipe", "pipe"] }).toString().toLowerCase();
3822
+ const { execFileSync: execFileSync4 } = await import("child_process");
3823
+ const whoisOutput = execFileSync4("whois", [domain], { timeout: 1e4, stdio: ["ignore", "pipe", "pipe"] }).toString().toLowerCase();
3824
3824
  available = whoisOutput.includes("domain not found") || whoisOutput.includes("no match") || whoisOutput.includes("not found") || whoisOutput.includes("no data found") || whoisOutput.includes("status: free") || whoisOutput.includes("no entries found");
3825
3825
  } catch {
3826
3826
  available = false;
@@ -4284,8 +4284,8 @@ var TunnelManager = class {
4284
4284
  return this.binPath;
4285
4285
  }
4286
4286
  try {
4287
- const { execFileSync: execFileSync3 } = await import("child_process");
4288
- const sysPath = execFileSync3("which", ["cloudflared"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
4287
+ const { execFileSync: execFileSync4 } = await import("child_process");
4288
+ const sysPath = execFileSync4("which", ["cloudflared"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
4289
4289
  if (sysPath && existsSync2(sysPath)) {
4290
4290
  this.binPath = sysPath;
4291
4291
  return sysPath;
@@ -5177,12 +5177,12 @@ var GatewayManager = class {
5177
5177
  zone = await this.cfClient.createZone(domain);
5178
5178
  }
5179
5179
  const existingRecords = await this.cfClient.listDnsRecords(zone.id);
5180
- const { homedir: homedir7 } = await import("os");
5181
- const backupDir = join4(homedir7(), ".agenticmail");
5180
+ const { homedir: homedir8 } = await import("os");
5181
+ const backupDir = join4(homedir8(), ".agenticmail");
5182
5182
  const backupPath = join4(backupDir, `dns-backup-${domain}-${Date.now()}.json`);
5183
- const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync4 } = await import("fs");
5184
- mkdirSync4(backupDir, { recursive: true });
5185
- writeFileSync4(backupPath, JSON.stringify({
5183
+ const { writeFileSync: writeFileSync5, mkdirSync: mkdirSync5 } = await import("fs");
5184
+ mkdirSync5(backupDir, { recursive: true });
5185
+ writeFileSync5(backupPath, JSON.stringify({
5186
5186
  domain,
5187
5187
  zoneId: zone.id,
5188
5188
  backedUpAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -5813,9 +5813,9 @@ var RELAY_PRESETS = {
5813
5813
 
5814
5814
  // src/setup/index.ts
5815
5815
  import { randomBytes as randomBytes2 } from "crypto";
5816
- import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, chmodSync } from "fs";
5817
- import { join as join7 } from "path";
5818
- import { homedir as homedir6 } from "os";
5816
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, chmodSync } from "fs";
5817
+ import { join as join8 } from "path";
5818
+ import { homedir as homedir7 } from "os";
5819
5819
 
5820
5820
  // src/setup/deps.ts
5821
5821
  import { execFileSync } from "child_process";
@@ -6301,6 +6301,440 @@ var DependencyInstaller = class {
6301
6301
  }
6302
6302
  };
6303
6303
 
6304
+ // src/setup/service.ts
6305
+ import { execFileSync as execFileSync3, execSync as execSync2 } from "child_process";
6306
+ import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
6307
+ import { join as join7 } from "path";
6308
+ import { homedir as homedir6, platform as platform3 } from "os";
6309
+ var PLIST_LABEL = "com.agenticmail.server";
6310
+ var SYSTEMD_UNIT = "agenticmail.service";
6311
+ var ServiceManager = class {
6312
+ os = platform3();
6313
+ /**
6314
+ * Get the path to the service file.
6315
+ */
6316
+ getServicePath() {
6317
+ if (this.os === "darwin") {
6318
+ return join7(homedir6(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
6319
+ } else {
6320
+ return join7(homedir6(), ".config", "systemd", "user", SYSTEMD_UNIT);
6321
+ }
6322
+ }
6323
+ /**
6324
+ * Find the Node.js binary path.
6325
+ */
6326
+ getNodePath() {
6327
+ try {
6328
+ return execFileSync3("which", ["node"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
6329
+ } catch {
6330
+ return process.execPath;
6331
+ }
6332
+ }
6333
+ /**
6334
+ * Find the API server entry point.
6335
+ * Searches common locations where agenticmail is installed.
6336
+ */
6337
+ getApiEntryPath() {
6338
+ const searchDirs = [
6339
+ // Global npm install
6340
+ join7(homedir6(), "node_modules", "agenticmail"),
6341
+ // npx cache / global prefix
6342
+ ...(() => {
6343
+ try {
6344
+ const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
6345
+ return [
6346
+ join7(prefix, "lib", "node_modules", "agenticmail"),
6347
+ join7(prefix, "node_modules", "agenticmail")
6348
+ ];
6349
+ } catch {
6350
+ return [];
6351
+ }
6352
+ })(),
6353
+ // Homebrew on macOS
6354
+ "/opt/homebrew/lib/node_modules/agenticmail",
6355
+ "/usr/local/lib/node_modules/agenticmail"
6356
+ ];
6357
+ for (const base of searchDirs) {
6358
+ const apiPaths = [
6359
+ join7(base, "node_modules", "@agenticmail", "api", "dist", "index.js"),
6360
+ join7(base, "..", "@agenticmail", "api", "dist", "index.js")
6361
+ ];
6362
+ for (const p of apiPaths) {
6363
+ if (existsSync5(p)) return p;
6364
+ }
6365
+ }
6366
+ const dataDir = join7(homedir6(), ".agenticmail");
6367
+ const entryCache = join7(dataDir, "api-entry.path");
6368
+ if (existsSync5(entryCache)) {
6369
+ const cached = readFileSync2(entryCache, "utf-8").trim();
6370
+ if (existsSync5(cached)) return cached;
6371
+ }
6372
+ throw new Error("Could not find @agenticmail/api entry point. Run `agenticmail start` first to populate the cache.");
6373
+ }
6374
+ /**
6375
+ * Cache the API entry path so the service can find it later.
6376
+ */
6377
+ cacheApiEntryPath(entryPath) {
6378
+ const dataDir = join7(homedir6(), ".agenticmail");
6379
+ if (!existsSync5(dataDir)) mkdirSync3(dataDir, { recursive: true });
6380
+ writeFileSync3(join7(dataDir, "api-entry.path"), entryPath);
6381
+ }
6382
+ /**
6383
+ * Get the current package version.
6384
+ */
6385
+ getVersion() {
6386
+ try {
6387
+ const pkgPaths = [
6388
+ join7(homedir6(), "node_modules", "agenticmail", "package.json"),
6389
+ join7(homedir6(), ".agenticmail", "package-version.json")
6390
+ ];
6391
+ try {
6392
+ const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
6393
+ pkgPaths.push(join7(prefix, "lib", "node_modules", "agenticmail", "package.json"));
6394
+ } catch {
6395
+ }
6396
+ for (const p of pkgPaths) {
6397
+ if (existsSync5(p)) {
6398
+ const pkg = JSON.parse(readFileSync2(p, "utf-8"));
6399
+ if (pkg.version) return pkg.version;
6400
+ }
6401
+ }
6402
+ } catch {
6403
+ }
6404
+ return "unknown";
6405
+ }
6406
+ /**
6407
+ * Generate a wrapper script that waits for Docker before starting the API.
6408
+ * This ensures AgenticMail doesn't fail on boot when Docker is still loading.
6409
+ */
6410
+ generateStartScript(nodePath, apiEntry) {
6411
+ const scriptPath = join7(homedir6(), ".agenticmail", "bin", "start-server.sh");
6412
+ const scriptDir = join7(homedir6(), ".agenticmail", "bin");
6413
+ if (!existsSync5(scriptDir)) mkdirSync3(scriptDir, { recursive: true });
6414
+ const script = [
6415
+ "#!/bin/bash",
6416
+ "# AgenticMail auto-start script",
6417
+ "# Waits for Docker to be ready, then starts the API server.",
6418
+ "",
6419
+ 'LOG_DIR="$HOME/.agenticmail/logs"',
6420
+ 'mkdir -p "$LOG_DIR"',
6421
+ "",
6422
+ "log() {",
6423
+ ` echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_DIR/startup.log"`,
6424
+ "}",
6425
+ "",
6426
+ 'log "AgenticMail starting..."',
6427
+ "",
6428
+ "# Wait for Docker daemon (up to 10 minutes \u2014 Docker Desktop can be very slow on first boot)",
6429
+ "MAX_WAIT=600",
6430
+ "WAITED=0",
6431
+ "while ! docker info >/dev/null 2>&1; do",
6432
+ " if [ $WAITED -ge $MAX_WAIT ]; then",
6433
+ ' log "ERROR: Docker did not start after ${MAX_WAIT}s. Exiting."',
6434
+ " exit 1",
6435
+ " fi",
6436
+ " sleep 5",
6437
+ " WAITED=$((WAITED + 5))",
6438
+ ' log "Waiting for Docker... (${WAITED}s)"',
6439
+ "done",
6440
+ 'log "Docker is ready (waited ${WAITED}s)"',
6441
+ "",
6442
+ "# Wait for Stalwart container (up to 60s)",
6443
+ "MAX_STALWART=60",
6444
+ "WAITED=0",
6445
+ 'while ! docker ps --filter "name=agenticmail-stalwart" --format "{{.Status}}" 2>/dev/null | grep -qi "up"; do',
6446
+ " if [ $WAITED -ge $MAX_STALWART ]; then",
6447
+ ' log "WARNING: Stalwart not running. Attempting to start..."',
6448
+ ' COMPOSE="$HOME/.agenticmail/docker-compose.yml"',
6449
+ ' if [ -f "$COMPOSE" ]; then',
6450
+ ' docker compose -f "$COMPOSE" up -d 2>>"$LOG_DIR/startup.log"',
6451
+ " sleep 5",
6452
+ " fi",
6453
+ " break",
6454
+ " fi",
6455
+ " sleep 3",
6456
+ " WAITED=$((WAITED + 3))",
6457
+ "done",
6458
+ 'log "Stalwart check complete"',
6459
+ "",
6460
+ "# Start the API server",
6461
+ `log "Starting API server: ${nodePath} ${apiEntry}"`,
6462
+ `exec "${nodePath}" "${apiEntry}"`
6463
+ ].join("\n") + "\n";
6464
+ writeFileSync3(scriptPath, script, { mode: 493 });
6465
+ return scriptPath;
6466
+ }
6467
+ /**
6468
+ * Generate the launchd plist content for macOS.
6469
+ * More robust than OpenClaw's plist:
6470
+ * - Wrapper script waits for Docker + Stalwart before starting
6471
+ * - KeepAlive: true (unconditional — always restart, not just on crash)
6472
+ * - SoftResourceLimits for file descriptors (email servers need many)
6473
+ * - StartInterval as backup heartbeat (checks every 5 min)
6474
+ * - Service version tracking in env vars
6475
+ */
6476
+ generatePlist(nodePath, apiEntry, configPath) {
6477
+ const config = JSON.parse(readFileSync2(configPath, "utf-8"));
6478
+ const logDir = join7(homedir6(), ".agenticmail", "logs");
6479
+ if (!existsSync5(logDir)) mkdirSync3(logDir, { recursive: true });
6480
+ const version = this.getVersion();
6481
+ const startScript = this.generateStartScript(nodePath, apiEntry);
6482
+ return `<?xml version="1.0" encoding="UTF-8"?>
6483
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
6484
+ <plist version="1.0">
6485
+ <dict>
6486
+ <key>Label</key>
6487
+ <string>${PLIST_LABEL}</string>
6488
+
6489
+ <key>Comment</key>
6490
+ <string>AgenticMail API Server (v${version})</string>
6491
+
6492
+ <key>ProgramArguments</key>
6493
+ <array>
6494
+ <string>${startScript}</string>
6495
+ </array>
6496
+
6497
+ <key>EnvironmentVariables</key>
6498
+ <dict>
6499
+ <key>HOME</key>
6500
+ <string>${homedir6()}</string>
6501
+ <key>AGENTICMAIL_DATA_DIR</key>
6502
+ <string>${config.dataDir || join7(homedir6(), ".agenticmail")}</string>
6503
+ <key>AGENTICMAIL_MASTER_KEY</key>
6504
+ <string>${config.masterKey}</string>
6505
+ <key>STALWART_ADMIN_USER</key>
6506
+ <string>${config.stalwart.adminUser}</string>
6507
+ <key>STALWART_ADMIN_PASSWORD</key>
6508
+ <string>${config.stalwart.adminPassword}</string>
6509
+ <key>STALWART_URL</key>
6510
+ <string>${config.stalwart.url}</string>
6511
+ <key>AGENTICMAIL_API_PORT</key>
6512
+ <string>${String(config.api.port)}</string>
6513
+ <key>AGENTICMAIL_API_HOST</key>
6514
+ <string>${config.api.host}</string>
6515
+ <key>SMTP_HOST</key>
6516
+ <string>${config.smtp.host}</string>
6517
+ <key>SMTP_PORT</key>
6518
+ <string>${String(config.smtp.port)}</string>
6519
+ <key>IMAP_HOST</key>
6520
+ <string>${config.imap.host}</string>
6521
+ <key>IMAP_PORT</key>
6522
+ <string>${String(config.imap.port)}</string>
6523
+ <key>PATH</key>
6524
+ <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
6525
+ <key>AGENTICMAIL_SERVICE_VERSION</key>
6526
+ <string>${version}</string>
6527
+ <key>AGENTICMAIL_SERVICE_LABEL</key>
6528
+ <string>${PLIST_LABEL}</string>
6529
+ </dict>
6530
+
6531
+ <!-- Start when user logs in -->
6532
+ <key>RunAtLoad</key>
6533
+ <true/>
6534
+
6535
+ <!-- Always keep running \u2014 restart unconditionally if it ever stops -->
6536
+ <key>KeepAlive</key>
6537
+ <true/>
6538
+
6539
+ <!-- Minimum 15s between restarts to avoid rapid crash loops -->
6540
+ <key>ThrottleInterval</key>
6541
+ <integer>15</integer>
6542
+
6543
+ <!-- File descriptor limits \u2014 email servers need many open connections -->
6544
+ <key>SoftResourceLimits</key>
6545
+ <dict>
6546
+ <key>NumberOfFiles</key>
6547
+ <integer>8192</integer>
6548
+ </dict>
6549
+ <key>HardResourceLimits</key>
6550
+ <dict>
6551
+ <key>NumberOfFiles</key>
6552
+ <integer>16384</integer>
6553
+ </dict>
6554
+
6555
+ <key>StandardOutPath</key>
6556
+ <string>${logDir}/server.log</string>
6557
+ <key>StandardErrorPath</key>
6558
+ <string>${logDir}/server.err.log</string>
6559
+
6560
+ <key>ProcessType</key>
6561
+ <string>Background</string>
6562
+ </dict>
6563
+ </plist>`;
6564
+ }
6565
+ /**
6566
+ * Generate the systemd user service content for Linux.
6567
+ * More robust than basic services:
6568
+ * - Wrapper script waits for Docker + Stalwart
6569
+ * - Restart=always (unconditional)
6570
+ * - WatchdogSec for health monitoring
6571
+ * - File descriptor limits
6572
+ * - Proper dependency ordering
6573
+ */
6574
+ generateSystemdUnit(nodePath, apiEntry, configPath) {
6575
+ const config = JSON.parse(readFileSync2(configPath, "utf-8"));
6576
+ const dataDir = config.dataDir || join7(homedir6(), ".agenticmail");
6577
+ const version = this.getVersion();
6578
+ const startScript = this.generateStartScript(nodePath, apiEntry);
6579
+ return `[Unit]
6580
+ Description=AgenticMail API Server (v${version})
6581
+ After=network-online.target docker.service
6582
+ Wants=network-online.target docker.service
6583
+ StartLimitIntervalSec=300
6584
+ StartLimitBurst=5
6585
+
6586
+ [Service]
6587
+ Type=simple
6588
+ ExecStart=${startScript}
6589
+ Restart=always
6590
+ RestartSec=15
6591
+ TimeoutStartSec=660
6592
+ LimitNOFILE=8192
6593
+ Environment=HOME=${homedir6()}
6594
+ Environment=AGENTICMAIL_DATA_DIR=${dataDir}
6595
+ Environment=AGENTICMAIL_MASTER_KEY=${config.masterKey}
6596
+ Environment=STALWART_ADMIN_USER=${config.stalwart.adminUser}
6597
+ Environment=STALWART_ADMIN_PASSWORD=${config.stalwart.adminPassword}
6598
+ Environment=STALWART_URL=${config.stalwart.url}
6599
+ Environment=AGENTICMAIL_API_PORT=${config.api.port}
6600
+ Environment=AGENTICMAIL_API_HOST=${config.api.host}
6601
+ Environment=SMTP_HOST=${config.smtp.host}
6602
+ Environment=SMTP_PORT=${config.smtp.port}
6603
+ Environment=IMAP_HOST=${config.imap.host}
6604
+ Environment=IMAP_PORT=${config.imap.port}
6605
+ Environment=PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin
6606
+ Environment=AGENTICMAIL_SERVICE_VERSION=${version}
6607
+
6608
+ [Install]
6609
+ WantedBy=default.target
6610
+ `;
6611
+ }
6612
+ /**
6613
+ * Install the auto-start service.
6614
+ */
6615
+ install() {
6616
+ const configPath = join7(homedir6(), ".agenticmail", "config.json");
6617
+ if (!existsSync5(configPath)) {
6618
+ return { installed: false, message: "Config not found. Run agenticmail setup first." };
6619
+ }
6620
+ const nodePath = this.getNodePath();
6621
+ let apiEntry;
6622
+ try {
6623
+ apiEntry = this.getApiEntryPath();
6624
+ } catch (err) {
6625
+ return { installed: false, message: err.message };
6626
+ }
6627
+ const servicePath = this.getServicePath();
6628
+ if (this.os === "darwin") {
6629
+ const dir = join7(homedir6(), "Library", "LaunchAgents");
6630
+ if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
6631
+ if (existsSync5(servicePath)) {
6632
+ try {
6633
+ execFileSync3("launchctl", ["unload", servicePath], { timeout: 1e4, stdio: "ignore" });
6634
+ } catch {
6635
+ }
6636
+ }
6637
+ const plist = this.generatePlist(nodePath, apiEntry, configPath);
6638
+ writeFileSync3(servicePath, plist);
6639
+ try {
6640
+ execFileSync3("launchctl", ["load", servicePath], { timeout: 1e4, stdio: "ignore" });
6641
+ } catch (err) {
6642
+ return { installed: false, message: `Failed to load service: ${err.message}` };
6643
+ }
6644
+ return { installed: true, message: `Service installed at ${servicePath}` };
6645
+ } else if (this.os === "linux") {
6646
+ const dir = join7(homedir6(), ".config", "systemd", "user");
6647
+ if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
6648
+ const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
6649
+ writeFileSync3(servicePath, unit);
6650
+ try {
6651
+ execFileSync3("systemctl", ["--user", "daemon-reload"], { timeout: 1e4, stdio: "ignore" });
6652
+ execFileSync3("systemctl", ["--user", "enable", SYSTEMD_UNIT], { timeout: 1e4, stdio: "ignore" });
6653
+ execFileSync3("systemctl", ["--user", "start", SYSTEMD_UNIT], { timeout: 1e4, stdio: "ignore" });
6654
+ try {
6655
+ execFileSync3("loginctl", ["enable-linger"], { timeout: 1e4, stdio: "ignore" });
6656
+ } catch {
6657
+ }
6658
+ } catch (err) {
6659
+ return { installed: false, message: `Failed to enable service: ${err.message}` };
6660
+ }
6661
+ return { installed: true, message: `Service installed at ${servicePath}` };
6662
+ } else {
6663
+ return { installed: false, message: `Auto-start not supported on ${this.os}` };
6664
+ }
6665
+ }
6666
+ /**
6667
+ * Uninstall the auto-start service.
6668
+ */
6669
+ uninstall() {
6670
+ const servicePath = this.getServicePath();
6671
+ if (!existsSync5(servicePath)) {
6672
+ return { removed: false, message: "Service is not installed." };
6673
+ }
6674
+ if (this.os === "darwin") {
6675
+ try {
6676
+ execFileSync3("launchctl", ["unload", servicePath], { timeout: 1e4, stdio: "ignore" });
6677
+ } catch {
6678
+ }
6679
+ try {
6680
+ unlinkSync(servicePath);
6681
+ } catch {
6682
+ }
6683
+ return { removed: true, message: "Service removed." };
6684
+ } else if (this.os === "linux") {
6685
+ try {
6686
+ execFileSync3("systemctl", ["--user", "stop", SYSTEMD_UNIT], { timeout: 1e4, stdio: "ignore" });
6687
+ execFileSync3("systemctl", ["--user", "disable", SYSTEMD_UNIT], { timeout: 1e4, stdio: "ignore" });
6688
+ } catch {
6689
+ }
6690
+ try {
6691
+ unlinkSync(servicePath);
6692
+ } catch {
6693
+ }
6694
+ try {
6695
+ execFileSync3("systemctl", ["--user", "daemon-reload"], { timeout: 1e4, stdio: "ignore" });
6696
+ } catch {
6697
+ }
6698
+ return { removed: true, message: "Service removed." };
6699
+ } else {
6700
+ return { removed: false, message: `Not supported on ${this.os}` };
6701
+ }
6702
+ }
6703
+ /**
6704
+ * Get the current service status.
6705
+ */
6706
+ status() {
6707
+ const servicePath = this.getServicePath();
6708
+ const plat = this.os === "darwin" ? "launchd" : this.os === "linux" ? "systemd" : "unsupported";
6709
+ const installed = existsSync5(servicePath);
6710
+ let running = false;
6711
+ if (installed) {
6712
+ if (this.os === "darwin") {
6713
+ try {
6714
+ const output = execSync2(`launchctl list | grep ${PLIST_LABEL}`, { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString();
6715
+ const pid = output.trim().split(" ")[0];
6716
+ running = pid !== "-" && pid !== "" && !isNaN(parseInt(pid));
6717
+ } catch {
6718
+ }
6719
+ } else if (this.os === "linux") {
6720
+ try {
6721
+ execFileSync3("systemctl", ["--user", "is-active", SYSTEMD_UNIT], { timeout: 5e3, stdio: "ignore" });
6722
+ running = true;
6723
+ } catch {
6724
+ }
6725
+ }
6726
+ }
6727
+ return { installed, running, platform: plat, servicePath: installed ? servicePath : null };
6728
+ }
6729
+ /**
6730
+ * Reinstall the service (useful after config changes or updates).
6731
+ */
6732
+ reinstall() {
6733
+ this.uninstall();
6734
+ return this.install();
6735
+ }
6736
+ };
6737
+
6304
6738
  // src/setup/index.ts
6305
6739
  var SetupManager = class {
6306
6740
  checker = new DependencyChecker();
@@ -6342,13 +6776,13 @@ var SetupManager = class {
6342
6776
  * falls back to monorepo location.
6343
6777
  */
6344
6778
  getComposePath() {
6345
- const standalonePath = join7(homedir6(), ".agenticmail", "docker-compose.yml");
6346
- if (existsSync5(standalonePath)) return standalonePath;
6779
+ const standalonePath = join8(homedir7(), ".agenticmail", "docker-compose.yml");
6780
+ if (existsSync6(standalonePath)) return standalonePath;
6347
6781
  const cwd = process.cwd();
6348
- const candidates = [cwd, join7(cwd, "..")];
6782
+ const candidates = [cwd, join8(cwd, "..")];
6349
6783
  for (const dir of candidates) {
6350
- const p = join7(dir, "docker-compose.yml");
6351
- if (existsSync5(p)) return p;
6784
+ const p = join8(dir, "docker-compose.yml");
6785
+ if (existsSync6(p)) return p;
6352
6786
  }
6353
6787
  return standalonePath;
6354
6788
  }
@@ -6358,19 +6792,19 @@ var SetupManager = class {
6358
6792
  * Always regenerates Docker files to keep passwords in sync.
6359
6793
  */
6360
6794
  initConfig() {
6361
- const dataDir = join7(homedir6(), ".agenticmail");
6362
- const configPath = join7(dataDir, "config.json");
6363
- const envPath = join7(dataDir, ".env");
6364
- if (existsSync5(configPath)) {
6795
+ const dataDir = join8(homedir7(), ".agenticmail");
6796
+ const configPath = join8(dataDir, "config.json");
6797
+ const envPath = join8(dataDir, ".env");
6798
+ if (existsSync6(configPath)) {
6365
6799
  try {
6366
- const existing = JSON.parse(readFileSync2(configPath, "utf-8"));
6800
+ const existing = JSON.parse(readFileSync3(configPath, "utf-8"));
6367
6801
  this.generateDockerFiles(existing);
6368
6802
  return { configPath, envPath, config: existing, isNew: false };
6369
6803
  } catch {
6370
6804
  }
6371
6805
  }
6372
- if (!existsSync5(dataDir)) {
6373
- mkdirSync3(dataDir, { recursive: true });
6806
+ if (!existsSync6(dataDir)) {
6807
+ mkdirSync4(dataDir, { recursive: true });
6374
6808
  }
6375
6809
  const masterKey = `mk_${randomBytes2(24).toString("hex")}`;
6376
6810
  const stalwartPassword = randomBytes2(16).toString("hex");
@@ -6386,7 +6820,7 @@ var SetupManager = class {
6386
6820
  api: { port: 3100, host: "127.0.0.1" },
6387
6821
  dataDir
6388
6822
  };
6389
- writeFileSync3(configPath, JSON.stringify(config, null, 2));
6823
+ writeFileSync4(configPath, JSON.stringify(config, null, 2));
6390
6824
  chmodSync(configPath, 384);
6391
6825
  const envContent = `# Auto-generated by agenticmail setup
6392
6826
  STALWART_ADMIN_USER=admin
@@ -6402,7 +6836,7 @@ SMTP_PORT=587
6402
6836
  IMAP_HOST=localhost
6403
6837
  IMAP_PORT=143
6404
6838
  `;
6405
- writeFileSync3(envPath, envContent);
6839
+ writeFileSync4(envPath, envContent);
6406
6840
  chmodSync(envPath, 384);
6407
6841
  this.generateDockerFiles(config);
6408
6842
  return { configPath, envPath, config, isNew: true };
@@ -6412,13 +6846,13 @@ IMAP_PORT=143
6412
6846
  * with the correct admin password from config.
6413
6847
  */
6414
6848
  generateDockerFiles(config) {
6415
- const dataDir = config.dataDir || join7(homedir6(), ".agenticmail");
6416
- if (!existsSync5(dataDir)) {
6417
- mkdirSync3(dataDir, { recursive: true });
6849
+ const dataDir = config.dataDir || join8(homedir7(), ".agenticmail");
6850
+ if (!existsSync6(dataDir)) {
6851
+ mkdirSync4(dataDir, { recursive: true });
6418
6852
  }
6419
6853
  const password = config.stalwart?.adminPassword || "changeme";
6420
- const composePath = join7(dataDir, "docker-compose.yml");
6421
- writeFileSync3(composePath, `services:
6854
+ const composePath = join8(dataDir, "docker-compose.yml");
6855
+ writeFileSync4(composePath, `services:
6422
6856
  stalwart:
6423
6857
  image: stalwartlabs/stalwart:latest
6424
6858
  container_name: agenticmail-stalwart
@@ -6440,8 +6874,8 @@ IMAP_PORT=143
6440
6874
  volumes:
6441
6875
  stalwart-data:
6442
6876
  `);
6443
- const tomlPath = join7(dataDir, "stalwart.toml");
6444
- writeFileSync3(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
6877
+ const tomlPath = join8(dataDir, "stalwart.toml");
6878
+ writeFileSync4(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
6445
6879
 
6446
6880
  [server]
6447
6881
  hostname = "localhost"
@@ -6496,8 +6930,8 @@ secret = "${password}"
6496
6930
  * Check if config has already been initialized.
6497
6931
  */
6498
6932
  isInitialized() {
6499
- const configPath = join7(homedir6(), ".agenticmail", "config.json");
6500
- return existsSync5(configPath);
6933
+ const configPath = join8(homedir7(), ".agenticmail", "config.json");
6934
+ return existsSync6(configPath);
6501
6935
  }
6502
6936
  };
6503
6937
  export {
@@ -6522,6 +6956,7 @@ export {
6522
6956
  RelayBridge,
6523
6957
  RelayGateway,
6524
6958
  SPAM_THRESHOLD,
6959
+ ServiceManager,
6525
6960
  SetupManager,
6526
6961
  SmsManager,
6527
6962
  SmsPoller,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/core",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Core SDK for AgenticMail — programmatic email for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",