@agenticmail/cli 0.9.38 → 0.9.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/README.md +9 -0
- 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 +95 -53
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -118,6 +118,15 @@ Uses your existing Gmail or Outlook account. You provide your email address and
|
|
|
118
118
|
|
|
119
119
|
Agent emails go out as sub-addresses like `yourname+agentname@gmail.com`. Replies come back through the same account.
|
|
120
120
|
|
|
121
|
+
> **Before you hit enter on `setup-email`, know what you're signing up for.** Once the relay is connected, every sub-agent on this machine is reachable from the public internet via plus-addressing:
|
|
122
|
+
>
|
|
123
|
+
> - Anyone who guesses `yourname+secretary@gmail.com`, `yourname+kepler@gmail.com`, … can email that agent and the dispatcher will wake a Claude / Codex turn to process the message. The `+sub` part is publicly guessable (`+secretary`, `+kepler`), not a secret.
|
|
124
|
+
> - External mail wakes the dispatcher identically to internal `@localhost` mail. Source doesn't matter; a new-mail SSE event is a new-mail SSE event.
|
|
125
|
+
> - The host bridges (`yourname+claudecode@gmail.com`, `yourname+codex@gmail.com`) take a special path — they route to `handleBridgeMail` which uses the host SDK's `resume` option to wake your last session headlessly, falling through to the bridge-escalation email at `setup_operator_email` if resume fails.
|
|
126
|
+
> - **Watch for spam.** Scrapers that find a plus-address can drive worker turns at your expense. The `wake-budget` guard in `dispatcher.handleEvent` is the automatic throttle; relay-level spam filtering is the cleaner long-term answer. For agents that should stay internal-only, leave them off the relay or fence them with `metadata.host`.
|
|
127
|
+
>
|
|
128
|
+
> If you'd rather keep everything local for now, skip `setup-email` entirely — agents talking to each other over `*@localhost` works fully without a relay.
|
|
129
|
+
|
|
121
130
|
### Domain Mode (For Professional Use)
|
|
122
131
|
|
|
123
132
|
Uses a custom domain with Cloudflare for DNS, email routing, and tunneling. The wizard:
|
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";
|
|
@@ -5067,15 +5068,27 @@ async function cmdSetupEmail() {
|
|
|
5067
5068
|
}
|
|
5068
5069
|
} catch {
|
|
5069
5070
|
}
|
|
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
5071
|
const GMAIL_DOMAINS = /* @__PURE__ */ new Set(["gmail.com", "googlemail.com"]);
|
|
5078
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();
|
|
5079
5092
|
let provider;
|
|
5080
5093
|
let smtpHost;
|
|
5081
5094
|
let smtpPort;
|
|
@@ -5117,60 +5130,89 @@ async function cmdSetupEmail() {
|
|
|
5117
5130
|
if (appPasswordHint) log2(` ${c2.dim(appPasswordHint)}`);
|
|
5118
5131
|
log2(` ${c2.dim("Spaces in the password are fine \u2014 we'll strip them.")}`);
|
|
5119
5132
|
log2("");
|
|
5120
|
-
const
|
|
5121
|
-
|
|
5122
|
-
|
|
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
|
+
}
|
|
5123
5147
|
log2("");
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
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);
|
|
5156
5184
|
}
|
|
5185
|
+
spinner.fail(`Couldn't reach the API: ${msg}`);
|
|
5157
5186
|
log2("");
|
|
5158
5187
|
process.exit(1);
|
|
5159
5188
|
}
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
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:`);
|
|
5163
5198
|
log2("");
|
|
5164
|
-
|
|
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;
|
|
5165
5211
|
}
|
|
5166
5212
|
log2("");
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
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}`);
|
|
5213
|
+
if (friendly.isAuthError) {
|
|
5214
|
+
info2("Check the email + password and re-run `agenticmail setup-email`.");
|
|
5215
|
+
}
|
|
5174
5216
|
log2("");
|
|
5175
5217
|
process.exit(1);
|
|
5176
5218
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.40",
|
|
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",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"prepublishOnly": "npm run build"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@agenticmail/api": "^0.9.
|
|
34
|
+
"@agenticmail/api": "^0.9.28",
|
|
35
35
|
"@agenticmail/core": "^0.9.7",
|
|
36
36
|
"json5": "^2.2.3"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@agenticmail/claudecode": "^0.2.
|
|
39
|
+
"@agenticmail/claudecode": "^0.2.22",
|
|
40
40
|
"@agenticmail/codex": "^0.1.16"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|