@agenticmail/cli 0.9.37 → 0.9.38

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.
Files changed (2) hide show
  1. package/dist/cli.js +188 -0
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -4996,6 +4996,185 @@ async function cmdSetupRelay() {
4996
4996
  process.exit(1);
4997
4997
  }
4998
4998
  }
4999
+ async function cmdSetupEmail() {
5000
+ const args = process.argv.slice(3);
5001
+ if (args.some((a) => a === "--help" || a === "-h" || a === "help")) {
5002
+ log2("");
5003
+ log2(` ${c2.pinkBg(" \u{1F380} agenticmail setup-email ")}`);
5004
+ log2("");
5005
+ log2(` ${c2.bold("Usage:")} agenticmail setup-email`);
5006
+ log2("");
5007
+ log2(` Minimal email-relay setup: enter your address, enter the password,`);
5008
+ log2(` done. Provider (Gmail, Outlook, custom) is detected from the domain.`);
5009
+ log2(` Password is collected via hidden stdin \u2014 your agent never sees it.`);
5010
+ log2("");
5011
+ log2(` Prereq: AgenticMail already bootstrapped (run \`agenticmail setup\` first).`);
5012
+ log2("");
5013
+ return;
5014
+ }
5015
+ const configPath = join(homedir(), ".agenticmail", "config.json");
5016
+ if (!existsSync2(configPath)) {
5017
+ log2("");
5018
+ fail2(`AgenticMail isn't set up yet \u2014 no config at ${c2.dim(configPath)}`);
5019
+ log2(` Run ${c2.cyan("agenticmail setup")} first, then come back to add your email.`);
5020
+ log2("");
5021
+ process.exit(1);
5022
+ }
5023
+ let config;
5024
+ try {
5025
+ config = JSON.parse(readFileSync2(configPath, "utf-8"));
5026
+ } catch (err) {
5027
+ log2("");
5028
+ fail2(`Could not read ${configPath}: ${err.message}`);
5029
+ log2("");
5030
+ process.exit(1);
5031
+ }
5032
+ log2("");
5033
+ log2(` ${c2.bold("\u{1F380} AgenticMail \u2014 connect your mailbox")} `);
5034
+ log2("");
5035
+ log2(` ${c2.dim("Two questions: your email, your password. Password input is")}`);
5036
+ log2(` ${c2.dim("hidden and never leaves this process \u2014 your agent doesn't see it.")}`);
5037
+ log2("");
5038
+ const apiBase = `http://${config.api.host}:${config.api.port}`;
5039
+ let serverReady = false;
5040
+ try {
5041
+ const probe = await fetch(`${apiBase}/api/agenticmail/health`, { signal: AbortSignal.timeout(2e3) });
5042
+ serverReady = probe.ok;
5043
+ } catch {
5044
+ }
5045
+ if (!serverReady) {
5046
+ try {
5047
+ serverReady = await startApiServer(config);
5048
+ } catch {
5049
+ }
5050
+ }
5051
+ if (!serverReady) {
5052
+ fail2(`API server not reachable at ${c2.cyan(apiBase)}`);
5053
+ info2(`Start it with ${c2.green("agenticmail start")}, then re-run this command.`);
5054
+ process.exit(1);
5055
+ }
5056
+ let agentName = "secretary";
5057
+ try {
5058
+ const acctResp = await fetch(`${apiBase}/api/agenticmail/accounts`, {
5059
+ headers: { "Authorization": `Bearer ${config.masterKey}` },
5060
+ signal: AbortSignal.timeout(5e3)
5061
+ });
5062
+ if (acctResp.ok) {
5063
+ const data = await acctResp.json();
5064
+ const agents = data?.agents ?? data ?? [];
5065
+ const first = agents.find((a) => a.name && a.name !== "claudecode" && a.name !== "codex") ?? agents[0];
5066
+ if (first?.name) agentName = first.name;
5067
+ }
5068
+ } catch {
5069
+ }
5070
+ const email = (await ask(` ${c2.cyan("Your email address:")} `)).trim();
5071
+ if (!email || !email.includes("@")) {
5072
+ log2("");
5073
+ fail2("That doesn't look like a valid email address.");
5074
+ process.exit(1);
5075
+ }
5076
+ const domain = email.split("@")[1].toLowerCase();
5077
+ const GMAIL_DOMAINS = /* @__PURE__ */ new Set(["gmail.com", "googlemail.com"]);
5078
+ const OUTLOOK_DOMAINS = /* @__PURE__ */ new Set(["outlook.com", "hotmail.com", "live.com", "msn.com"]);
5079
+ let provider;
5080
+ let smtpHost;
5081
+ let smtpPort;
5082
+ let imapHost;
5083
+ let imapPort;
5084
+ let appPasswordHint = "";
5085
+ if (GMAIL_DOMAINS.has(domain)) {
5086
+ provider = "gmail";
5087
+ appPasswordHint = `App password: ${c2.cyan("https://myaccount.google.com/apppasswords")}`;
5088
+ } else if (OUTLOOK_DOMAINS.has(domain)) {
5089
+ provider = "outlook";
5090
+ appPasswordHint = `App password: your Microsoft account \u2192 Security \u2192 Advanced security options \u2192 App passwords`;
5091
+ } else {
5092
+ log2("");
5093
+ log2(` ${c2.dim("We don't recognize the domain ")}${c2.bold(domain)}${c2.dim(". Where does it live?")}`);
5094
+ log2(` ${c2.cyan("1.")} Google Workspace ${c2.dim("(mail hosted by Gmail)")}`);
5095
+ log2(` ${c2.cyan("2.")} Microsoft 365 ${c2.dim("(mail hosted by Outlook)")}`);
5096
+ log2(` ${c2.cyan("3.")} Custom mail server`);
5097
+ const pickProv = await pick(` ${c2.magenta(">")} `, ["1", "2", "3"]);
5098
+ if (pickProv === "1") {
5099
+ provider = "gmail";
5100
+ appPasswordHint = `App password: ${c2.cyan("https://myaccount.google.com/apppasswords")}`;
5101
+ } else if (pickProv === "2") {
5102
+ provider = "outlook";
5103
+ appPasswordHint = `App password: your Microsoft account \u2192 Security \u2192 Advanced security options \u2192 App passwords`;
5104
+ } else {
5105
+ provider = "custom";
5106
+ log2("");
5107
+ log2(` ${c2.dim("Your mail-server hostnames (check your provider's docs):")}`);
5108
+ smtpHost = (await ask(` ${c2.cyan("Outgoing (SMTP) host:")} `)).trim();
5109
+ const smtpPortStr = (await ask(` ${c2.cyan("SMTP port")} ${c2.dim("(587)")}: `)).trim();
5110
+ smtpPort = smtpPortStr ? parseInt(smtpPortStr, 10) : 587;
5111
+ imapHost = (await ask(` ${c2.cyan("Incoming (IMAP) host:")} `)).trim();
5112
+ const imapPortStr = (await ask(` ${c2.cyan("IMAP port")} ${c2.dim("(993)")}: `)).trim();
5113
+ imapPort = imapPortStr ? parseInt(imapPortStr, 10) : 993;
5114
+ }
5115
+ }
5116
+ log2("");
5117
+ if (appPasswordHint) log2(` ${c2.dim(appPasswordHint)}`);
5118
+ log2(` ${c2.dim("Spaces in the password are fine \u2014 we'll strip them.")}`);
5119
+ log2("");
5120
+ const rawPassword = await askSecret(` ${c2.cyan("Password:")} `);
5121
+ const password = rawPassword.replace(/\s+/g, "");
5122
+ if (!password) {
5123
+ log2("");
5124
+ fail2("No password entered.");
5125
+ process.exit(1);
5126
+ }
5127
+ log2("");
5128
+ const spinner = new Spinner("relay");
5129
+ spinner.start();
5130
+ try {
5131
+ const response = await fetch(`${apiBase}/api/agenticmail/gateway/relay`, {
5132
+ method: "POST",
5133
+ headers: {
5134
+ "Authorization": `Bearer ${config.masterKey}`,
5135
+ "Content-Type": "application/json"
5136
+ },
5137
+ body: JSON.stringify({
5138
+ provider,
5139
+ email,
5140
+ password,
5141
+ agentName,
5142
+ smtpHost,
5143
+ smtpPort,
5144
+ imapHost,
5145
+ imapPort
5146
+ }),
5147
+ signal: AbortSignal.timeout(3e4)
5148
+ });
5149
+ if (!response.ok) {
5150
+ const text = await response.text();
5151
+ const friendly = parseFriendlyError(text);
5152
+ spinner.fail(friendly.message);
5153
+ log2("");
5154
+ if (friendly.isAuthError) {
5155
+ info2("Check the email + password and run `agenticmail setup-email` again.");
5156
+ }
5157
+ log2("");
5158
+ process.exit(1);
5159
+ }
5160
+ const data = await response.json();
5161
+ spinner.succeed(`Mailbox connected \u2014 ${c2.bold(email)} ${c2.dim("via " + provider)}`);
5162
+ if (data?.agent?.subAddress) {
5163
+ log2("");
5164
+ ok2(`Agent ${c2.bold('"' + (data.agent.name ?? agentName) + '"')} ready at ${c2.cyan(data.agent.subAddress)}`);
5165
+ }
5166
+ log2("");
5167
+ log2(` ${c2.bold("Next:")} point bridge-escalation alerts at your personal email:`);
5168
+ log2("");
5169
+ log2(` ${c2.cyan("Option A")} \u2014 tell your host agent: "set my operator notification email to <you@example.com>"`);
5170
+ log2(` ${c2.cyan("Option B")} \u2014 open the web UI \u2192 click your avatar \u2192 ${c2.bold("Alert email")} \u2192 type, Save`);
5171
+ log2("");
5172
+ } catch (err) {
5173
+ spinner.fail(`Setup-email failed: ${err.message}`);
5174
+ log2("");
5175
+ process.exit(1);
5176
+ }
5177
+ }
4999
5178
  async function cmdSetup() {
5000
5179
  const setupArgs = process.argv.slice(3);
5001
5180
  if (setupArgs.some((a) => a === "--help" || a === "-h" || a === "help")) {
@@ -7468,6 +7647,14 @@ switch (command) {
7468
7647
  process.exit(1);
7469
7648
  });
7470
7649
  break;
7650
+ case "setup-email":
7651
+ case "email":
7652
+ case "connect-email":
7653
+ cmdSetupEmail().catch((err) => {
7654
+ console.error(err);
7655
+ process.exit(1);
7656
+ });
7657
+ break;
7471
7658
  case "start":
7472
7659
  cmdStart().catch((err) => {
7473
7660
  console.error(err);
@@ -7559,6 +7746,7 @@ switch (command) {
7559
7746
  log2(` ${c2.green("agenticmail")} Get started (setup + start)`);
7560
7747
  log2(` ${c2.green("agenticmail bootstrap")} ${c2.dim("Zero-question install \u2014 for AI agents (Claude Code) to run on a user's behalf")}`);
7561
7748
  log2(` ${c2.green("agenticmail setup")} Re-run the setup wizard ${c2.dim("(use --yes for non-interactive)")}`);
7749
+ log2(` ${c2.green("agenticmail setup-email")} Connect your mailbox \u2014 just email + password ${c2.dim("(auto-detects Gmail/Outlook/custom)")}`);
7562
7750
  log2(` ${c2.green("agenticmail start")} Start the server`);
7563
7751
  log2(` ${c2.green("agenticmail stop")} Stop the server`);
7564
7752
  log2(` ${c2.green("agenticmail status")} See what's running`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/cli",
3
- "version": "0.9.37",
3
+ "version": "0.9.38",
4
4
  "description": "Email and SMS infrastructure for AI agents — the first platform to give agents real email addresses and phone numbers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",