@agenticmail/cli 0.9.37 → 0.9.39
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/bin-claudecode.js +1 -0
- package/dist/bin-codex.js +1 -0
- package/dist/chunk-EHUD3MJT.js +10 -0
- package/dist/cli.js +230 -0
- package/package.json +1 -1
package/dist/bin-claudecode.js
CHANGED
package/dist/bin-codex.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/suppress-experimental-warnings.ts
|
|
2
|
+
{
|
|
3
|
+
const originalEmit = process.emit.bind(process);
|
|
4
|
+
process.emit = function(name, ...args) {
|
|
5
|
+
if (name === "warning" && args[0] && typeof args[0] === "object" && "name" in args[0] && args[0].name === "ExperimentalWarning" && "message" in args[0] && typeof args[0].message === "string" && /\bSQLite\b/i.test(args[0].message)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
return originalEmit(name, ...args);
|
|
9
|
+
};
|
|
10
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-EHUD3MJT.js";
|
|
2
3
|
|
|
3
4
|
// src/cli.ts
|
|
4
5
|
import { createInterface as createInterface2, emitKeypressEvents as emitKeypressEvents2 } from "readline";
|
|
@@ -4996,6 +4997,226 @@ async function cmdSetupRelay() {
|
|
|
4996
4997
|
process.exit(1);
|
|
4997
4998
|
}
|
|
4998
4999
|
}
|
|
5000
|
+
async function cmdSetupEmail() {
|
|
5001
|
+
const args = process.argv.slice(3);
|
|
5002
|
+
if (args.some((a) => a === "--help" || a === "-h" || a === "help")) {
|
|
5003
|
+
log2("");
|
|
5004
|
+
log2(` ${c2.pinkBg(" \u{1F380} agenticmail setup-email ")}`);
|
|
5005
|
+
log2("");
|
|
5006
|
+
log2(` ${c2.bold("Usage:")} agenticmail setup-email`);
|
|
5007
|
+
log2("");
|
|
5008
|
+
log2(` Minimal email-relay setup: enter your address, enter the password,`);
|
|
5009
|
+
log2(` done. Provider (Gmail, Outlook, custom) is detected from the domain.`);
|
|
5010
|
+
log2(` Password is collected via hidden stdin \u2014 your agent never sees it.`);
|
|
5011
|
+
log2("");
|
|
5012
|
+
log2(` Prereq: AgenticMail already bootstrapped (run \`agenticmail setup\` first).`);
|
|
5013
|
+
log2("");
|
|
5014
|
+
return;
|
|
5015
|
+
}
|
|
5016
|
+
const configPath = join(homedir(), ".agenticmail", "config.json");
|
|
5017
|
+
if (!existsSync2(configPath)) {
|
|
5018
|
+
log2("");
|
|
5019
|
+
fail2(`AgenticMail isn't set up yet \u2014 no config at ${c2.dim(configPath)}`);
|
|
5020
|
+
log2(` Run ${c2.cyan("agenticmail setup")} first, then come back to add your email.`);
|
|
5021
|
+
log2("");
|
|
5022
|
+
process.exit(1);
|
|
5023
|
+
}
|
|
5024
|
+
let config;
|
|
5025
|
+
try {
|
|
5026
|
+
config = JSON.parse(readFileSync2(configPath, "utf-8"));
|
|
5027
|
+
} catch (err) {
|
|
5028
|
+
log2("");
|
|
5029
|
+
fail2(`Could not read ${configPath}: ${err.message}`);
|
|
5030
|
+
log2("");
|
|
5031
|
+
process.exit(1);
|
|
5032
|
+
}
|
|
5033
|
+
log2("");
|
|
5034
|
+
log2(` ${c2.bold("\u{1F380} AgenticMail \u2014 connect your mailbox")} `);
|
|
5035
|
+
log2("");
|
|
5036
|
+
log2(` ${c2.dim("Two questions: your email, your password. Password input is")}`);
|
|
5037
|
+
log2(` ${c2.dim("hidden and never leaves this process \u2014 your agent doesn't see it.")}`);
|
|
5038
|
+
log2("");
|
|
5039
|
+
const apiBase = `http://${config.api.host}:${config.api.port}`;
|
|
5040
|
+
let serverReady = false;
|
|
5041
|
+
try {
|
|
5042
|
+
const probe = await fetch(`${apiBase}/api/agenticmail/health`, { signal: AbortSignal.timeout(2e3) });
|
|
5043
|
+
serverReady = probe.ok;
|
|
5044
|
+
} catch {
|
|
5045
|
+
}
|
|
5046
|
+
if (!serverReady) {
|
|
5047
|
+
try {
|
|
5048
|
+
serverReady = await startApiServer(config);
|
|
5049
|
+
} catch {
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
if (!serverReady) {
|
|
5053
|
+
fail2(`API server not reachable at ${c2.cyan(apiBase)}`);
|
|
5054
|
+
info2(`Start it with ${c2.green("agenticmail start")}, then re-run this command.`);
|
|
5055
|
+
process.exit(1);
|
|
5056
|
+
}
|
|
5057
|
+
let agentName = "secretary";
|
|
5058
|
+
try {
|
|
5059
|
+
const acctResp = await fetch(`${apiBase}/api/agenticmail/accounts`, {
|
|
5060
|
+
headers: { "Authorization": `Bearer ${config.masterKey}` },
|
|
5061
|
+
signal: AbortSignal.timeout(5e3)
|
|
5062
|
+
});
|
|
5063
|
+
if (acctResp.ok) {
|
|
5064
|
+
const data = await acctResp.json();
|
|
5065
|
+
const agents = data?.agents ?? data ?? [];
|
|
5066
|
+
const first = agents.find((a) => a.name && a.name !== "claudecode" && a.name !== "codex") ?? agents[0];
|
|
5067
|
+
if (first?.name) agentName = first.name;
|
|
5068
|
+
}
|
|
5069
|
+
} catch {
|
|
5070
|
+
}
|
|
5071
|
+
const GMAIL_DOMAINS = /* @__PURE__ */ new Set(["gmail.com", "googlemail.com"]);
|
|
5072
|
+
const OUTLOOK_DOMAINS = /* @__PURE__ */ new Set(["outlook.com", "hotmail.com", "live.com", "msn.com"]);
|
|
5073
|
+
const EMAIL_SHAPE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
5074
|
+
const MAX_EMAIL_ATTEMPTS = 5;
|
|
5075
|
+
let email = "";
|
|
5076
|
+
for (let attempt = 1; attempt <= MAX_EMAIL_ATTEMPTS; attempt++) {
|
|
5077
|
+
const raw = (await ask(` ${c2.cyan("Your email address:")} `)).trim();
|
|
5078
|
+
if (EMAIL_SHAPE.test(raw)) {
|
|
5079
|
+
email = raw;
|
|
5080
|
+
break;
|
|
5081
|
+
}
|
|
5082
|
+
fail2(`That doesn't look like a valid email address${raw ? ` (${raw})` : ""}.`);
|
|
5083
|
+
if (attempt === MAX_EMAIL_ATTEMPTS) {
|
|
5084
|
+
log2("");
|
|
5085
|
+
info2("Too many invalid attempts \u2014 exiting. Re-run `agenticmail setup-email` when ready.");
|
|
5086
|
+
log2("");
|
|
5087
|
+
process.exit(1);
|
|
5088
|
+
}
|
|
5089
|
+
info2(`Try again ${c2.dim(`(attempt ${attempt + 1} of ${MAX_EMAIL_ATTEMPTS})`)}`);
|
|
5090
|
+
}
|
|
5091
|
+
const domain = email.split("@")[1].toLowerCase();
|
|
5092
|
+
let provider;
|
|
5093
|
+
let smtpHost;
|
|
5094
|
+
let smtpPort;
|
|
5095
|
+
let imapHost;
|
|
5096
|
+
let imapPort;
|
|
5097
|
+
let appPasswordHint = "";
|
|
5098
|
+
if (GMAIL_DOMAINS.has(domain)) {
|
|
5099
|
+
provider = "gmail";
|
|
5100
|
+
appPasswordHint = `App password: ${c2.cyan("https://myaccount.google.com/apppasswords")}`;
|
|
5101
|
+
} else if (OUTLOOK_DOMAINS.has(domain)) {
|
|
5102
|
+
provider = "outlook";
|
|
5103
|
+
appPasswordHint = `App password: your Microsoft account \u2192 Security \u2192 Advanced security options \u2192 App passwords`;
|
|
5104
|
+
} else {
|
|
5105
|
+
log2("");
|
|
5106
|
+
log2(` ${c2.dim("We don't recognize the domain ")}${c2.bold(domain)}${c2.dim(". Where does it live?")}`);
|
|
5107
|
+
log2(` ${c2.cyan("1.")} Google Workspace ${c2.dim("(mail hosted by Gmail)")}`);
|
|
5108
|
+
log2(` ${c2.cyan("2.")} Microsoft 365 ${c2.dim("(mail hosted by Outlook)")}`);
|
|
5109
|
+
log2(` ${c2.cyan("3.")} Custom mail server`);
|
|
5110
|
+
const pickProv = await pick(` ${c2.magenta(">")} `, ["1", "2", "3"]);
|
|
5111
|
+
if (pickProv === "1") {
|
|
5112
|
+
provider = "gmail";
|
|
5113
|
+
appPasswordHint = `App password: ${c2.cyan("https://myaccount.google.com/apppasswords")}`;
|
|
5114
|
+
} else if (pickProv === "2") {
|
|
5115
|
+
provider = "outlook";
|
|
5116
|
+
appPasswordHint = `App password: your Microsoft account \u2192 Security \u2192 Advanced security options \u2192 App passwords`;
|
|
5117
|
+
} else {
|
|
5118
|
+
provider = "custom";
|
|
5119
|
+
log2("");
|
|
5120
|
+
log2(` ${c2.dim("Your mail-server hostnames (check your provider's docs):")}`);
|
|
5121
|
+
smtpHost = (await ask(` ${c2.cyan("Outgoing (SMTP) host:")} `)).trim();
|
|
5122
|
+
const smtpPortStr = (await ask(` ${c2.cyan("SMTP port")} ${c2.dim("(587)")}: `)).trim();
|
|
5123
|
+
smtpPort = smtpPortStr ? parseInt(smtpPortStr, 10) : 587;
|
|
5124
|
+
imapHost = (await ask(` ${c2.cyan("Incoming (IMAP) host:")} `)).trim();
|
|
5125
|
+
const imapPortStr = (await ask(` ${c2.cyan("IMAP port")} ${c2.dim("(993)")}: `)).trim();
|
|
5126
|
+
imapPort = imapPortStr ? parseInt(imapPortStr, 10) : 993;
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
log2("");
|
|
5130
|
+
if (appPasswordHint) log2(` ${c2.dim(appPasswordHint)}`);
|
|
5131
|
+
log2(` ${c2.dim("Spaces in the password are fine \u2014 we'll strip them.")}`);
|
|
5132
|
+
log2("");
|
|
5133
|
+
const MAX_PASSWORD_ATTEMPTS = 3;
|
|
5134
|
+
for (let attempt = 1; attempt <= MAX_PASSWORD_ATTEMPTS; attempt++) {
|
|
5135
|
+
const rawPassword = await askSecret(` ${c2.cyan("Password:")} `);
|
|
5136
|
+
const password = rawPassword.replace(/\s+/g, "");
|
|
5137
|
+
if (!password) {
|
|
5138
|
+
fail2("No password entered.");
|
|
5139
|
+
if (attempt === MAX_PASSWORD_ATTEMPTS) {
|
|
5140
|
+
info2("Exiting \u2014 re-run `agenticmail setup-email` when ready.");
|
|
5141
|
+
log2("");
|
|
5142
|
+
process.exit(1);
|
|
5143
|
+
}
|
|
5144
|
+
info2(`Try again ${c2.dim(`(attempt ${attempt + 1} of ${MAX_PASSWORD_ATTEMPTS})`)}`);
|
|
5145
|
+
continue;
|
|
5146
|
+
}
|
|
5147
|
+
log2("");
|
|
5148
|
+
const spinner = new Spinner("relay");
|
|
5149
|
+
spinner.start();
|
|
5150
|
+
let response;
|
|
5151
|
+
try {
|
|
5152
|
+
response = await fetch(`${apiBase}/api/agenticmail/gateway/relay`, {
|
|
5153
|
+
method: "POST",
|
|
5154
|
+
headers: {
|
|
5155
|
+
"Authorization": `Bearer ${config.masterKey}`,
|
|
5156
|
+
"Content-Type": "application/json"
|
|
5157
|
+
},
|
|
5158
|
+
body: JSON.stringify({
|
|
5159
|
+
provider,
|
|
5160
|
+
email,
|
|
5161
|
+
password,
|
|
5162
|
+
agentName,
|
|
5163
|
+
smtpHost,
|
|
5164
|
+
smtpPort,
|
|
5165
|
+
imapHost,
|
|
5166
|
+
imapPort
|
|
5167
|
+
}),
|
|
5168
|
+
signal: AbortSignal.timeout(9e4)
|
|
5169
|
+
});
|
|
5170
|
+
} catch (err) {
|
|
5171
|
+
const msg = err.message;
|
|
5172
|
+
const isTimeout = msg.includes("aborted due to timeout") || err.name === "TimeoutError" || err.name === "AbortError";
|
|
5173
|
+
if (isTimeout) {
|
|
5174
|
+
spinner.fail("Mail server took too long to respond (>90 s).");
|
|
5175
|
+
if (attempt < MAX_PASSWORD_ATTEMPTS) {
|
|
5176
|
+
log2(` ${c2.yellow("Could be a flaky link or a slow IMAP handshake. Try again.")} ${c2.dim(`(attempt ${attempt + 1} of ${MAX_PASSWORD_ATTEMPTS})`)}`);
|
|
5177
|
+
log2("");
|
|
5178
|
+
continue;
|
|
5179
|
+
}
|
|
5180
|
+
log2("");
|
|
5181
|
+
info2("If this keeps happening, check the API logs at ~/.agenticmail/logs/server.log");
|
|
5182
|
+
log2("");
|
|
5183
|
+
process.exit(1);
|
|
5184
|
+
}
|
|
5185
|
+
spinner.fail(`Couldn't reach the API: ${msg}`);
|
|
5186
|
+
log2("");
|
|
5187
|
+
process.exit(1);
|
|
5188
|
+
}
|
|
5189
|
+
if (response.ok) {
|
|
5190
|
+
const data = await response.json();
|
|
5191
|
+
spinner.succeed(`Mailbox connected \u2014 ${c2.bold(email)} ${c2.dim("via " + provider)}`);
|
|
5192
|
+
if (data?.agent?.subAddress) {
|
|
5193
|
+
log2("");
|
|
5194
|
+
ok2(`Agent ${c2.bold('"' + (data.agent.name ?? agentName) + '"')} ready at ${c2.cyan(data.agent.subAddress)}`);
|
|
5195
|
+
}
|
|
5196
|
+
log2("");
|
|
5197
|
+
log2(` ${c2.bold("Next:")} point bridge-escalation alerts at your personal email:`);
|
|
5198
|
+
log2("");
|
|
5199
|
+
log2(` ${c2.cyan("Option A")} \u2014 tell your host agent: "set my operator notification email to <you@example.com>"`);
|
|
5200
|
+
log2(` ${c2.cyan("Option B")} \u2014 open the web UI \u2192 click your avatar \u2192 ${c2.bold("Alert email")} \u2192 type, Save`);
|
|
5201
|
+
log2("");
|
|
5202
|
+
return;
|
|
5203
|
+
}
|
|
5204
|
+
const text = await response.text();
|
|
5205
|
+
const friendly = parseFriendlyError(text);
|
|
5206
|
+
spinner.fail(friendly.message);
|
|
5207
|
+
if (friendly.isAuthError && attempt < MAX_PASSWORD_ATTEMPTS) {
|
|
5208
|
+
log2(` ${c2.yellow("Wrong password \u2014 try again.")} ${c2.dim(`(attempt ${attempt + 1} of ${MAX_PASSWORD_ATTEMPTS})`)}`);
|
|
5209
|
+
log2("");
|
|
5210
|
+
continue;
|
|
5211
|
+
}
|
|
5212
|
+
log2("");
|
|
5213
|
+
if (friendly.isAuthError) {
|
|
5214
|
+
info2("Check the email + password and re-run `agenticmail setup-email`.");
|
|
5215
|
+
}
|
|
5216
|
+
log2("");
|
|
5217
|
+
process.exit(1);
|
|
5218
|
+
}
|
|
5219
|
+
}
|
|
4999
5220
|
async function cmdSetup() {
|
|
5000
5221
|
const setupArgs = process.argv.slice(3);
|
|
5001
5222
|
if (setupArgs.some((a) => a === "--help" || a === "-h" || a === "help")) {
|
|
@@ -7468,6 +7689,14 @@ switch (command) {
|
|
|
7468
7689
|
process.exit(1);
|
|
7469
7690
|
});
|
|
7470
7691
|
break;
|
|
7692
|
+
case "setup-email":
|
|
7693
|
+
case "email":
|
|
7694
|
+
case "connect-email":
|
|
7695
|
+
cmdSetupEmail().catch((err) => {
|
|
7696
|
+
console.error(err);
|
|
7697
|
+
process.exit(1);
|
|
7698
|
+
});
|
|
7699
|
+
break;
|
|
7471
7700
|
case "start":
|
|
7472
7701
|
cmdStart().catch((err) => {
|
|
7473
7702
|
console.error(err);
|
|
@@ -7559,6 +7788,7 @@ switch (command) {
|
|
|
7559
7788
|
log2(` ${c2.green("agenticmail")} Get started (setup + start)`);
|
|
7560
7789
|
log2(` ${c2.green("agenticmail bootstrap")} ${c2.dim("Zero-question install \u2014 for AI agents (Claude Code) to run on a user's behalf")}`);
|
|
7561
7790
|
log2(` ${c2.green("agenticmail setup")} Re-run the setup wizard ${c2.dim("(use --yes for non-interactive)")}`);
|
|
7791
|
+
log2(` ${c2.green("agenticmail setup-email")} Connect your mailbox \u2014 just email + password ${c2.dim("(auto-detects Gmail/Outlook/custom)")}`);
|
|
7562
7792
|
log2(` ${c2.green("agenticmail start")} Start the server`);
|
|
7563
7793
|
log2(` ${c2.green("agenticmail stop")} Stop the server`);
|
|
7564
7794
|
log2(` ${c2.green("agenticmail status")} See what's running`);
|
package/package.json
CHANGED