agenticmail 0.5.28 → 0.5.30
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/cli.js +36 -28
- package/package.json +3 -1
- package/scripts/uninstall.mjs +98 -0
package/dist/cli.js
CHANGED
|
@@ -4627,8 +4627,8 @@ async function cmdSetup() {
|
|
|
4627
4627
|
}
|
|
4628
4628
|
await new Promise((r) => setTimeout(r, 300));
|
|
4629
4629
|
}
|
|
4630
|
-
const
|
|
4631
|
-
if (!
|
|
4630
|
+
const stalwartDep = deps.find((d) => d.name === "stalwart");
|
|
4631
|
+
if (!stalwartDep?.installed) {
|
|
4632
4632
|
const spinner = new Spinner("stalwart");
|
|
4633
4633
|
spinner.start();
|
|
4634
4634
|
const stalwartSetup = new SetupManager((msg) => spinner.update(msg));
|
|
@@ -4640,6 +4640,11 @@ async function cmdSetup() {
|
|
|
4640
4640
|
process.exit(1);
|
|
4641
4641
|
}
|
|
4642
4642
|
} else {
|
|
4643
|
+
ok2(`${c2.bold("Mail Server")} ${c2.dim("\u2014 already running")}`);
|
|
4644
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
4645
|
+
}
|
|
4646
|
+
{
|
|
4647
|
+
let stalwartAuthOk = false;
|
|
4643
4648
|
try {
|
|
4644
4649
|
const authCheck = await fetch(`${result.config.stalwart.url}/api/principal`, {
|
|
4645
4650
|
headers: {
|
|
@@ -4647,36 +4652,33 @@ async function cmdSetup() {
|
|
|
4647
4652
|
},
|
|
4648
4653
|
signal: AbortSignal.timeout(5e3)
|
|
4649
4654
|
});
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4655
|
+
stalwartAuthOk = authCheck.status !== 401;
|
|
4656
|
+
} catch {
|
|
4657
|
+
}
|
|
4658
|
+
if (!stalwartAuthOk) {
|
|
4659
|
+
const spinner = new Spinner("stalwart", "Resetting mail server (stale credentials)...");
|
|
4660
|
+
spinner.start();
|
|
4661
|
+
try {
|
|
4662
|
+
const { execFileSync } = await import("child_process");
|
|
4663
|
+
execFileSync("docker", ["rm", "-f", "agenticmail-stalwart"], { timeout: 15e3, stdio: "ignore" });
|
|
4653
4664
|
try {
|
|
4654
|
-
const
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
).toString().trim();
|
|
4662
|
-
for (const vol of volumes.split("\n").filter(Boolean)) {
|
|
4663
|
-
execFileSync("docker", ["volume", "rm", vol], { timeout: 1e4, stdio: "ignore" });
|
|
4664
|
-
}
|
|
4665
|
-
} catch {
|
|
4665
|
+
const volumes = execFileSync(
|
|
4666
|
+
"docker",
|
|
4667
|
+
["volume", "ls", "-q", "--filter", "name=stalwart-data"],
|
|
4668
|
+
{ timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }
|
|
4669
|
+
).toString().trim();
|
|
4670
|
+
for (const vol of volumes.split("\n").filter(Boolean)) {
|
|
4671
|
+
execFileSync("docker", ["volume", "rm", vol], { timeout: 1e4, stdio: "ignore" });
|
|
4666
4672
|
}
|
|
4667
|
-
|
|
4668
|
-
spinner.succeed(`${c2.bold("Mail Server")} \u2014 recreated with fresh credentials`);
|
|
4669
|
-
} catch (err) {
|
|
4670
|
-
spinner.fail(`Couldn't reset mail server: ${err.message}`);
|
|
4671
|
-
process.exit(1);
|
|
4673
|
+
} catch {
|
|
4672
4674
|
}
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
+
await setup.ensureStalwart();
|
|
4676
|
+
spinner.succeed(`${c2.bold("Mail Server")} \u2014 recreated with fresh credentials`);
|
|
4677
|
+
} catch (err) {
|
|
4678
|
+
spinner.fail(`Couldn't reset mail server: ${err.message}`);
|
|
4679
|
+
process.exit(1);
|
|
4675
4680
|
}
|
|
4676
|
-
} catch {
|
|
4677
|
-
ok2(`${c2.bold("Mail Server")} ${c2.dim("\u2014 already running")}`);
|
|
4678
4681
|
}
|
|
4679
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
4680
4682
|
}
|
|
4681
4683
|
const cf = deps.find((d) => d.name === "cloudflared");
|
|
4682
4684
|
if (!cf?.installed) {
|
|
@@ -5208,7 +5210,13 @@ function parseFriendlyError(rawText) {
|
|
|
5208
5210
|
isAuthError: true
|
|
5209
5211
|
};
|
|
5210
5212
|
}
|
|
5211
|
-
if (error.includes("
|
|
5213
|
+
if (error.includes("Stalwart API error") && (error.includes("401") || error.includes("Unauthorized"))) {
|
|
5214
|
+
return {
|
|
5215
|
+
message: "Mail server credentials mismatch \u2014 the container may have stale data. Run: agenticmail setup",
|
|
5216
|
+
isAuthError: false
|
|
5217
|
+
};
|
|
5218
|
+
}
|
|
5219
|
+
if (error.includes("Invalid API key") || error.includes("Master API key required")) {
|
|
5212
5220
|
return {
|
|
5213
5221
|
message: "Server authorization failed \u2014 the mail server may still be starting up. Try again in a moment.",
|
|
5214
5222
|
isAuthError: false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agenticmail",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.30",
|
|
4
4
|
"description": "Email and SMS infrastructure for AI agents \u2014 the first platform to give agents real email addresses and phone numbers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
+
"scripts",
|
|
19
20
|
"README.md",
|
|
20
21
|
"REFERENCE.md",
|
|
21
22
|
"LICENSE"
|
|
@@ -23,6 +24,7 @@
|
|
|
23
24
|
"scripts": {
|
|
24
25
|
"build": "tsup src/index.ts src/cli.ts --format esm --dts --clean",
|
|
25
26
|
"test": "vitest run --passWithNoTests",
|
|
27
|
+
"preuninstall": "node scripts/uninstall.mjs",
|
|
26
28
|
"prepublishOnly": "npm run build"
|
|
27
29
|
},
|
|
28
30
|
"dependencies": {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cleanup script that runs on `npm uninstall agenticmail`.
|
|
5
|
+
*
|
|
6
|
+
* 1. Unloads & removes the launchd / systemd auto-start service
|
|
7
|
+
* 2. Stops & removes the agenticmail-stalwart Docker container
|
|
8
|
+
* 3. Cleans agenticmail entries from OpenClaw config
|
|
9
|
+
* 4. Removes ~/.agenticmail data directory
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
13
|
+
import { readFileSync, writeFileSync, existsSync, rmSync, unlinkSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { homedir, platform } from 'node:os';
|
|
16
|
+
|
|
17
|
+
const home = homedir();
|
|
18
|
+
const os = platform();
|
|
19
|
+
|
|
20
|
+
function log(msg) { console.log(`[agenticmail] ${msg}`); }
|
|
21
|
+
function tryExec(cmd, opts = {}) { try { execSync(cmd, { timeout: 15_000, stdio: 'ignore', ...opts }); } catch { /* ignore */ } }
|
|
22
|
+
|
|
23
|
+
// ── 1. Unload auto-start service ─────────────────────────────────
|
|
24
|
+
|
|
25
|
+
if (os === 'darwin') {
|
|
26
|
+
const plist = join(home, 'Library', 'LaunchAgents', 'com.agenticmail.server.plist');
|
|
27
|
+
if (existsSync(plist)) {
|
|
28
|
+
log('Unloading launchd service...');
|
|
29
|
+
tryExec(`launchctl bootout gui/$(id -u) "${plist}"`);
|
|
30
|
+
try { unlinkSync(plist); } catch { /* ignore */ }
|
|
31
|
+
}
|
|
32
|
+
} else if (os === 'linux') {
|
|
33
|
+
const unit = 'agenticmail.service';
|
|
34
|
+
tryExec(`systemctl --user stop ${unit}`);
|
|
35
|
+
tryExec(`systemctl --user disable ${unit}`);
|
|
36
|
+
const unitPath = join(home, '.config', 'systemd', 'user', unit);
|
|
37
|
+
if (existsSync(unitPath)) {
|
|
38
|
+
try { unlinkSync(unitPath); } catch { /* ignore */ }
|
|
39
|
+
tryExec('systemctl --user daemon-reload');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── 2. Stop Docker container ──────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const ps = execFileSync('docker', ['ps', '-a', '--filter', 'name=agenticmail-stalwart', '--format', '{{.Names}}'],
|
|
47
|
+
{ timeout: 10_000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
48
|
+
if (ps.includes('agenticmail-stalwart')) {
|
|
49
|
+
log('Stopping mail server container...');
|
|
50
|
+
tryExec('docker rm -f agenticmail-stalwart');
|
|
51
|
+
}
|
|
52
|
+
} catch { /* docker not available — skip */ }
|
|
53
|
+
|
|
54
|
+
// ── 3. Clean OpenClaw config ──────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
const openclawConfig = join(home, '.openclaw', 'openclaw.json');
|
|
57
|
+
if (existsSync(openclawConfig)) {
|
|
58
|
+
try {
|
|
59
|
+
const raw = readFileSync(openclawConfig, 'utf-8');
|
|
60
|
+
const config = JSON.parse(raw);
|
|
61
|
+
let changed = false;
|
|
62
|
+
|
|
63
|
+
// Remove plugins.entries.agenticmail
|
|
64
|
+
if (config.plugins?.entries?.agenticmail) {
|
|
65
|
+
delete config.plugins.entries.agenticmail;
|
|
66
|
+
changed = true;
|
|
67
|
+
if (Object.keys(config.plugins.entries).length === 0) delete config.plugins.entries;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Remove our path from plugins.load.paths
|
|
71
|
+
if (Array.isArray(config.plugins?.load?.paths)) {
|
|
72
|
+
const before = config.plugins.load.paths.length;
|
|
73
|
+
config.plugins.load.paths = config.plugins.load.paths.filter(
|
|
74
|
+
(p) => !p.includes('@agenticmail')
|
|
75
|
+
);
|
|
76
|
+
if (config.plugins.load.paths.length !== before) changed = true;
|
|
77
|
+
if (config.plugins.load.paths.length === 0) {
|
|
78
|
+
delete config.plugins.load.paths;
|
|
79
|
+
if (config.plugins.load && Object.keys(config.plugins.load).length === 0) delete config.plugins.load;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (changed) {
|
|
84
|
+
writeFileSync(openclawConfig, JSON.stringify(config, null, 2) + '\n');
|
|
85
|
+
log('Cleaned OpenClaw config');
|
|
86
|
+
}
|
|
87
|
+
} catch { /* don't fail uninstall */ }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── 4. Remove ~/.agenticmail ──────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
const dataDir = join(home, '.agenticmail');
|
|
93
|
+
if (existsSync(dataDir)) {
|
|
94
|
+
log('Removing ~/.agenticmail/ ...');
|
|
95
|
+
try { rmSync(dataDir, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
log('Uninstall complete.');
|