@agenticmail/core 0.5.56 → 0.5.59
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.cjs +170 -38
- package/dist/index.d.cts +46 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.js +169 -38
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1238,7 +1238,8 @@ var InboxWatcher = class extends import_node_events.EventEmitter {
|
|
|
1238
1238
|
this.emit("close");
|
|
1239
1239
|
this._scheduleReconnect();
|
|
1240
1240
|
});
|
|
1241
|
-
|
|
1241
|
+
lock.release();
|
|
1242
|
+
this._lock = null;
|
|
1242
1243
|
} catch (err) {
|
|
1243
1244
|
lock.release();
|
|
1244
1245
|
throw err;
|
|
@@ -1917,7 +1918,15 @@ var AccountManager = class {
|
|
|
1917
1918
|
}
|
|
1918
1919
|
const principalName = options.name.toLowerCase();
|
|
1919
1920
|
const email = `${principalName}@${domain}`;
|
|
1921
|
+
const existingAgent = await this.getByName(options.name);
|
|
1922
|
+
if (existingAgent != null) {
|
|
1923
|
+
throw new Error(`Account already exists: ${options.name}`);
|
|
1924
|
+
}
|
|
1920
1925
|
await this.stalwart.ensureDomain(domain);
|
|
1926
|
+
try {
|
|
1927
|
+
await this.stalwart.deletePrincipal(principalName);
|
|
1928
|
+
} catch {
|
|
1929
|
+
}
|
|
1921
1930
|
await this.stalwart.createPrincipal({
|
|
1922
1931
|
type: "individual",
|
|
1923
1932
|
name: principalName,
|
|
@@ -7068,6 +7077,8 @@ var import_node_child_process4 = require("child_process");
|
|
|
7068
7077
|
var import_node_fs6 = require("fs");
|
|
7069
7078
|
var import_node_path7 = require("path");
|
|
7070
7079
|
var import_node_os6 = require("os");
|
|
7080
|
+
var import_node_module = require("module");
|
|
7081
|
+
var import_meta = {};
|
|
7071
7082
|
var PLIST_LABEL = "com.agenticmail.server";
|
|
7072
7083
|
var SYSTEMD_UNIT = "agenticmail.service";
|
|
7073
7084
|
var ServiceManager = class {
|
|
@@ -7094,42 +7105,59 @@ var ServiceManager = class {
|
|
|
7094
7105
|
}
|
|
7095
7106
|
/**
|
|
7096
7107
|
* Find the API server entry point.
|
|
7097
|
-
*
|
|
7108
|
+
*
|
|
7109
|
+
* Issue #26 — Robust path resolution.
|
|
7110
|
+
*
|
|
7111
|
+
* The original implementation hard-coded `node_modules/agenticmail` (the
|
|
7112
|
+
* old unscoped package name). After the rename to `@agenticmail/cli`, that
|
|
7113
|
+
* directory no longer exists, so the resolver fell back to the stale
|
|
7114
|
+
* `~/.agenticmail/api-entry.path` cache and the launchd plist kept pointing
|
|
7115
|
+
* at a deleted path — causing the boot crash loop reported in #26.
|
|
7116
|
+
*
|
|
7117
|
+
* We now prefer `require.resolve('@agenticmail/api')` so the resolution
|
|
7118
|
+
* follows the actual installed location regardless of npm prefix, the
|
|
7119
|
+
* scoped vs unscoped package name, or the package manager (npm global,
|
|
7120
|
+
* pnpm, yarn global, local node_modules). Cached paths are always
|
|
7121
|
+
* validated against the filesystem before being returned.
|
|
7098
7122
|
*/
|
|
7099
7123
|
getApiEntryPath() {
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
} catch {
|
|
7112
|
-
return [];
|
|
7113
|
-
}
|
|
7114
|
-
})(),
|
|
7115
|
-
// Homebrew on macOS
|
|
7116
|
-
"/opt/homebrew/lib/node_modules/agenticmail",
|
|
7117
|
-
"/usr/local/lib/node_modules/agenticmail"
|
|
7124
|
+
try {
|
|
7125
|
+
const req = (0, import_node_module.createRequire)(import_meta.url);
|
|
7126
|
+
const resolved = req.resolve("@agenticmail/api");
|
|
7127
|
+
if ((0, import_node_fs6.existsSync)(resolved)) return resolved;
|
|
7128
|
+
} catch {
|
|
7129
|
+
}
|
|
7130
|
+
const parentPackages = [
|
|
7131
|
+
(0, import_node_path7.join)("@agenticmail", "cli"),
|
|
7132
|
+
// current scoped package
|
|
7133
|
+
"agenticmail"
|
|
7134
|
+
// legacy unscoped package
|
|
7118
7135
|
];
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7136
|
+
const baseDirs = [
|
|
7137
|
+
// user-local install
|
|
7138
|
+
(0, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules")
|
|
7139
|
+
];
|
|
7140
|
+
try {
|
|
7141
|
+
const prefix = (0, import_node_child_process4.execSync)("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
7142
|
+
baseDirs.push((0, import_node_path7.join)(prefix, "lib", "node_modules"));
|
|
7143
|
+
baseDirs.push((0, import_node_path7.join)(prefix, "node_modules"));
|
|
7144
|
+
} catch {
|
|
7145
|
+
}
|
|
7146
|
+
baseDirs.push("/opt/homebrew/lib/node_modules");
|
|
7147
|
+
baseDirs.push("/usr/local/lib/node_modules");
|
|
7148
|
+
for (const base of baseDirs) {
|
|
7149
|
+
const sibling = (0, import_node_path7.join)(base, "@agenticmail", "api", "dist", "index.js");
|
|
7150
|
+
if ((0, import_node_fs6.existsSync)(sibling)) return sibling;
|
|
7151
|
+
for (const parent of parentPackages) {
|
|
7152
|
+
const nested = (0, import_node_path7.join)(base, parent, "node_modules", "@agenticmail", "api", "dist", "index.js");
|
|
7153
|
+
if ((0, import_node_fs6.existsSync)(nested)) return nested;
|
|
7126
7154
|
}
|
|
7127
7155
|
}
|
|
7128
7156
|
const dataDir = (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail");
|
|
7129
7157
|
const entryCache = (0, import_node_path7.join)(dataDir, "api-entry.path");
|
|
7130
7158
|
if ((0, import_node_fs6.existsSync)(entryCache)) {
|
|
7131
7159
|
const cached = (0, import_node_fs6.readFileSync)(entryCache, "utf-8").trim();
|
|
7132
|
-
if ((0, import_node_fs6.existsSync)(cached)) return cached;
|
|
7160
|
+
if (cached && (0, import_node_fs6.existsSync)(cached)) return cached;
|
|
7133
7161
|
}
|
|
7134
7162
|
throw new Error("Could not find @agenticmail/api entry point. Run `agenticmail start` first to populate the cache.");
|
|
7135
7163
|
}
|
|
@@ -7143,25 +7171,49 @@ var ServiceManager = class {
|
|
|
7143
7171
|
}
|
|
7144
7172
|
/**
|
|
7145
7173
|
* Get the current package version.
|
|
7174
|
+
*
|
|
7175
|
+
* Issue #26 — resolve the CLI package.json via require.resolve so the
|
|
7176
|
+
* version reflects the *currently installed* @agenticmail/cli, not a
|
|
7177
|
+
* leftover unscoped `agenticmail` package directory.
|
|
7146
7178
|
*/
|
|
7147
7179
|
getVersion() {
|
|
7148
7180
|
try {
|
|
7149
|
-
const
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
const prefix = (0, import_node_child_process4.execSync)("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
7155
|
-
pkgPaths.push((0, import_node_path7.join)(prefix, "lib", "node_modules", "agenticmail", "package.json"));
|
|
7156
|
-
} catch {
|
|
7181
|
+
const req = (0, import_node_module.createRequire)(import_meta.url);
|
|
7182
|
+
const pkgJson = req.resolve("@agenticmail/cli/package.json");
|
|
7183
|
+
if ((0, import_node_fs6.existsSync)(pkgJson)) {
|
|
7184
|
+
const pkg = JSON.parse((0, import_node_fs6.readFileSync)(pkgJson, "utf-8"));
|
|
7185
|
+
if (pkg.version) return pkg.version;
|
|
7157
7186
|
}
|
|
7158
|
-
|
|
7187
|
+
} catch {
|
|
7188
|
+
}
|
|
7189
|
+
try {
|
|
7190
|
+
const apiEntry = this.getApiEntryPath();
|
|
7191
|
+
const apiPkg = (0, import_node_path7.join)(apiEntry, "..", "..", "package.json");
|
|
7192
|
+
if ((0, import_node_fs6.existsSync)(apiPkg)) {
|
|
7193
|
+
const pkg = JSON.parse((0, import_node_fs6.readFileSync)(apiPkg, "utf-8"));
|
|
7194
|
+
if (pkg.version) return pkg.version;
|
|
7195
|
+
}
|
|
7196
|
+
} catch {
|
|
7197
|
+
}
|
|
7198
|
+
const candidates = [
|
|
7199
|
+
(0, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules", "@agenticmail", "cli", "package.json"),
|
|
7200
|
+
(0, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules", "agenticmail", "package.json"),
|
|
7201
|
+
(0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "package-version.json")
|
|
7202
|
+
];
|
|
7203
|
+
try {
|
|
7204
|
+
const prefix = (0, import_node_child_process4.execSync)("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
7205
|
+
candidates.push((0, import_node_path7.join)(prefix, "lib", "node_modules", "@agenticmail", "cli", "package.json"));
|
|
7206
|
+
candidates.push((0, import_node_path7.join)(prefix, "lib", "node_modules", "agenticmail", "package.json"));
|
|
7207
|
+
} catch {
|
|
7208
|
+
}
|
|
7209
|
+
for (const p of candidates) {
|
|
7210
|
+
try {
|
|
7159
7211
|
if ((0, import_node_fs6.existsSync)(p)) {
|
|
7160
7212
|
const pkg = JSON.parse((0, import_node_fs6.readFileSync)(p, "utf-8"));
|
|
7161
7213
|
if (pkg.version) return pkg.version;
|
|
7162
7214
|
}
|
|
7215
|
+
} catch {
|
|
7163
7216
|
}
|
|
7164
|
-
} catch {
|
|
7165
7217
|
}
|
|
7166
7218
|
return "unknown";
|
|
7167
7219
|
}
|
|
@@ -7467,6 +7519,86 @@ WantedBy=default.target
|
|
|
7467
7519
|
this.uninstall();
|
|
7468
7520
|
return this.install();
|
|
7469
7521
|
}
|
|
7522
|
+
/**
|
|
7523
|
+
* Issue #26 — Detect a stale service installation.
|
|
7524
|
+
*
|
|
7525
|
+
* Background: when a user upgrades from the old unscoped `agenticmail`
|
|
7526
|
+
* package to the new `@agenticmail/cli` scoped package, the old
|
|
7527
|
+
* ~/Library/LaunchAgents/com.agenticmail.server.plist and
|
|
7528
|
+
* ~/.agenticmail/bin/start-server.sh files keep pointing at
|
|
7529
|
+
* /opt/homebrew/lib/node_modules/agenticmail/... — a path that no longer
|
|
7530
|
+
* exists post-rename. The result is a launchd crash loop.
|
|
7531
|
+
*
|
|
7532
|
+
* `needsRepair()` returns a non-null reason whenever:
|
|
7533
|
+
* - the service file exists but the start-server.sh it launches is
|
|
7534
|
+
* missing or references a node_modules path that no longer resolves;
|
|
7535
|
+
* - the embedded service version drifts from the running CLI version
|
|
7536
|
+
* (so service files get refreshed on every upgrade — including
|
|
7537
|
+
* in-place version bumps that don't change the install path);
|
|
7538
|
+
* - the cached API entry path no longer exists on disk.
|
|
7539
|
+
*
|
|
7540
|
+
* Returns null when everything checks out — callers should treat that as
|
|
7541
|
+
* "no action needed".
|
|
7542
|
+
*
|
|
7543
|
+
* Platform-aware: only inspects launchd artefacts on darwin and systemd
|
|
7544
|
+
* artefacts on linux. Returns null on unsupported platforms so this can
|
|
7545
|
+
* be called unconditionally from the CLI's start path.
|
|
7546
|
+
*/
|
|
7547
|
+
needsRepair() {
|
|
7548
|
+
if (this.os !== "darwin" && this.os !== "linux") return null;
|
|
7549
|
+
const servicePath = this.getServicePath();
|
|
7550
|
+
if (!(0, import_node_fs6.existsSync)(servicePath)) return null;
|
|
7551
|
+
let serviceContent = "";
|
|
7552
|
+
try {
|
|
7553
|
+
serviceContent = (0, import_node_fs6.readFileSync)(servicePath, "utf-8");
|
|
7554
|
+
} catch {
|
|
7555
|
+
return { reason: "Service file unreadable" };
|
|
7556
|
+
}
|
|
7557
|
+
const startScript = (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin", "start-server.sh");
|
|
7558
|
+
if (serviceContent.includes(startScript)) {
|
|
7559
|
+
if (!(0, import_node_fs6.existsSync)(startScript)) {
|
|
7560
|
+
return { reason: "start-server.sh is missing" };
|
|
7561
|
+
}
|
|
7562
|
+
let scriptContent = "";
|
|
7563
|
+
try {
|
|
7564
|
+
scriptContent = (0, import_node_fs6.readFileSync)(startScript, "utf-8");
|
|
7565
|
+
} catch {
|
|
7566
|
+
return { reason: "start-server.sh unreadable" };
|
|
7567
|
+
}
|
|
7568
|
+
const apiPathMatch = scriptContent.match(/(\/[^"\s]+@agenticmail\/api\/dist\/index\.js)/);
|
|
7569
|
+
if (apiPathMatch) {
|
|
7570
|
+
const referenced = apiPathMatch[1];
|
|
7571
|
+
if (!(0, import_node_fs6.existsSync)(referenced)) {
|
|
7572
|
+
return { reason: `start-server.sh references missing path: ${referenced}` };
|
|
7573
|
+
}
|
|
7574
|
+
}
|
|
7575
|
+
if (/node_modules\/agenticmail\/(?!.*@agenticmail\/cli)/.test(scriptContent)) {
|
|
7576
|
+
const stale = /(\S*node_modules\/agenticmail\/\S*)/.exec(scriptContent)?.[1];
|
|
7577
|
+
if (stale && !(0, import_node_fs6.existsSync)(stale)) {
|
|
7578
|
+
return { reason: `start-server.sh references legacy unscoped path: ${stale}` };
|
|
7579
|
+
}
|
|
7580
|
+
}
|
|
7581
|
+
} else {
|
|
7582
|
+
return { reason: "Service file does not reference the wrapper script" };
|
|
7583
|
+
}
|
|
7584
|
+
const currentVersion = this.getVersion();
|
|
7585
|
+
if (currentVersion !== "unknown") {
|
|
7586
|
+
if (!serviceContent.includes(`v${currentVersion}`) || !serviceContent.includes(`AGENTICMAIL_SERVICE_VERSION`) || !serviceContent.includes(currentVersion)) {
|
|
7587
|
+
return { reason: `Service version drift (current CLI is v${currentVersion})` };
|
|
7588
|
+
}
|
|
7589
|
+
}
|
|
7590
|
+
const entryCache = (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "api-entry.path");
|
|
7591
|
+
if ((0, import_node_fs6.existsSync)(entryCache)) {
|
|
7592
|
+
try {
|
|
7593
|
+
const cached = (0, import_node_fs6.readFileSync)(entryCache, "utf-8").trim();
|
|
7594
|
+
if (cached && !(0, import_node_fs6.existsSync)(cached)) {
|
|
7595
|
+
return { reason: `Cached API entry path no longer exists: ${cached}` };
|
|
7596
|
+
}
|
|
7597
|
+
} catch {
|
|
7598
|
+
}
|
|
7599
|
+
}
|
|
7600
|
+
return null;
|
|
7601
|
+
}
|
|
7470
7602
|
};
|
|
7471
7603
|
|
|
7472
7604
|
// src/setup/index.ts
|
package/dist/index.d.cts
CHANGED
|
@@ -1558,7 +1558,20 @@ declare class ServiceManager {
|
|
|
1558
1558
|
private getNodePath;
|
|
1559
1559
|
/**
|
|
1560
1560
|
* Find the API server entry point.
|
|
1561
|
-
*
|
|
1561
|
+
*
|
|
1562
|
+
* Issue #26 — Robust path resolution.
|
|
1563
|
+
*
|
|
1564
|
+
* The original implementation hard-coded `node_modules/agenticmail` (the
|
|
1565
|
+
* old unscoped package name). After the rename to `@agenticmail/cli`, that
|
|
1566
|
+
* directory no longer exists, so the resolver fell back to the stale
|
|
1567
|
+
* `~/.agenticmail/api-entry.path` cache and the launchd plist kept pointing
|
|
1568
|
+
* at a deleted path — causing the boot crash loop reported in #26.
|
|
1569
|
+
*
|
|
1570
|
+
* We now prefer `require.resolve('@agenticmail/api')` so the resolution
|
|
1571
|
+
* follows the actual installed location regardless of npm prefix, the
|
|
1572
|
+
* scoped vs unscoped package name, or the package manager (npm global,
|
|
1573
|
+
* pnpm, yarn global, local node_modules). Cached paths are always
|
|
1574
|
+
* validated against the filesystem before being returned.
|
|
1562
1575
|
*/
|
|
1563
1576
|
private getApiEntryPath;
|
|
1564
1577
|
/**
|
|
@@ -1567,6 +1580,10 @@ declare class ServiceManager {
|
|
|
1567
1580
|
cacheApiEntryPath(entryPath: string): void;
|
|
1568
1581
|
/**
|
|
1569
1582
|
* Get the current package version.
|
|
1583
|
+
*
|
|
1584
|
+
* Issue #26 — resolve the CLI package.json via require.resolve so the
|
|
1585
|
+
* version reflects the *currently installed* @agenticmail/cli, not a
|
|
1586
|
+
* leftover unscoped `agenticmail` package directory.
|
|
1570
1587
|
*/
|
|
1571
1588
|
private getVersion;
|
|
1572
1589
|
/**
|
|
@@ -1619,6 +1636,34 @@ declare class ServiceManager {
|
|
|
1619
1636
|
installed: boolean;
|
|
1620
1637
|
message: string;
|
|
1621
1638
|
};
|
|
1639
|
+
/**
|
|
1640
|
+
* Issue #26 — Detect a stale service installation.
|
|
1641
|
+
*
|
|
1642
|
+
* Background: when a user upgrades from the old unscoped `agenticmail`
|
|
1643
|
+
* package to the new `@agenticmail/cli` scoped package, the old
|
|
1644
|
+
* ~/Library/LaunchAgents/com.agenticmail.server.plist and
|
|
1645
|
+
* ~/.agenticmail/bin/start-server.sh files keep pointing at
|
|
1646
|
+
* /opt/homebrew/lib/node_modules/agenticmail/... — a path that no longer
|
|
1647
|
+
* exists post-rename. The result is a launchd crash loop.
|
|
1648
|
+
*
|
|
1649
|
+
* `needsRepair()` returns a non-null reason whenever:
|
|
1650
|
+
* - the service file exists but the start-server.sh it launches is
|
|
1651
|
+
* missing or references a node_modules path that no longer resolves;
|
|
1652
|
+
* - the embedded service version drifts from the running CLI version
|
|
1653
|
+
* (so service files get refreshed on every upgrade — including
|
|
1654
|
+
* in-place version bumps that don't change the install path);
|
|
1655
|
+
* - the cached API entry path no longer exists on disk.
|
|
1656
|
+
*
|
|
1657
|
+
* Returns null when everything checks out — callers should treat that as
|
|
1658
|
+
* "no action needed".
|
|
1659
|
+
*
|
|
1660
|
+
* Platform-aware: only inspects launchd artefacts on darwin and systemd
|
|
1661
|
+
* artefacts on linux. Returns null on unsupported platforms so this can
|
|
1662
|
+
* be called unconditionally from the CLI's start path.
|
|
1663
|
+
*/
|
|
1664
|
+
needsRepair(): {
|
|
1665
|
+
reason: string;
|
|
1666
|
+
} | null;
|
|
1622
1667
|
}
|
|
1623
1668
|
|
|
1624
1669
|
interface SetupConfig {
|
package/dist/index.d.ts
CHANGED
|
@@ -1558,7 +1558,20 @@ declare class ServiceManager {
|
|
|
1558
1558
|
private getNodePath;
|
|
1559
1559
|
/**
|
|
1560
1560
|
* Find the API server entry point.
|
|
1561
|
-
*
|
|
1561
|
+
*
|
|
1562
|
+
* Issue #26 — Robust path resolution.
|
|
1563
|
+
*
|
|
1564
|
+
* The original implementation hard-coded `node_modules/agenticmail` (the
|
|
1565
|
+
* old unscoped package name). After the rename to `@agenticmail/cli`, that
|
|
1566
|
+
* directory no longer exists, so the resolver fell back to the stale
|
|
1567
|
+
* `~/.agenticmail/api-entry.path` cache and the launchd plist kept pointing
|
|
1568
|
+
* at a deleted path — causing the boot crash loop reported in #26.
|
|
1569
|
+
*
|
|
1570
|
+
* We now prefer `require.resolve('@agenticmail/api')` so the resolution
|
|
1571
|
+
* follows the actual installed location regardless of npm prefix, the
|
|
1572
|
+
* scoped vs unscoped package name, or the package manager (npm global,
|
|
1573
|
+
* pnpm, yarn global, local node_modules). Cached paths are always
|
|
1574
|
+
* validated against the filesystem before being returned.
|
|
1562
1575
|
*/
|
|
1563
1576
|
private getApiEntryPath;
|
|
1564
1577
|
/**
|
|
@@ -1567,6 +1580,10 @@ declare class ServiceManager {
|
|
|
1567
1580
|
cacheApiEntryPath(entryPath: string): void;
|
|
1568
1581
|
/**
|
|
1569
1582
|
* Get the current package version.
|
|
1583
|
+
*
|
|
1584
|
+
* Issue #26 — resolve the CLI package.json via require.resolve so the
|
|
1585
|
+
* version reflects the *currently installed* @agenticmail/cli, not a
|
|
1586
|
+
* leftover unscoped `agenticmail` package directory.
|
|
1570
1587
|
*/
|
|
1571
1588
|
private getVersion;
|
|
1572
1589
|
/**
|
|
@@ -1619,6 +1636,34 @@ declare class ServiceManager {
|
|
|
1619
1636
|
installed: boolean;
|
|
1620
1637
|
message: string;
|
|
1621
1638
|
};
|
|
1639
|
+
/**
|
|
1640
|
+
* Issue #26 — Detect a stale service installation.
|
|
1641
|
+
*
|
|
1642
|
+
* Background: when a user upgrades from the old unscoped `agenticmail`
|
|
1643
|
+
* package to the new `@agenticmail/cli` scoped package, the old
|
|
1644
|
+
* ~/Library/LaunchAgents/com.agenticmail.server.plist and
|
|
1645
|
+
* ~/.agenticmail/bin/start-server.sh files keep pointing at
|
|
1646
|
+
* /opt/homebrew/lib/node_modules/agenticmail/... — a path that no longer
|
|
1647
|
+
* exists post-rename. The result is a launchd crash loop.
|
|
1648
|
+
*
|
|
1649
|
+
* `needsRepair()` returns a non-null reason whenever:
|
|
1650
|
+
* - the service file exists but the start-server.sh it launches is
|
|
1651
|
+
* missing or references a node_modules path that no longer resolves;
|
|
1652
|
+
* - the embedded service version drifts from the running CLI version
|
|
1653
|
+
* (so service files get refreshed on every upgrade — including
|
|
1654
|
+
* in-place version bumps that don't change the install path);
|
|
1655
|
+
* - the cached API entry path no longer exists on disk.
|
|
1656
|
+
*
|
|
1657
|
+
* Returns null when everything checks out — callers should treat that as
|
|
1658
|
+
* "no action needed".
|
|
1659
|
+
*
|
|
1660
|
+
* Platform-aware: only inspects launchd artefacts on darwin and systemd
|
|
1661
|
+
* artefacts on linux. Returns null on unsupported platforms so this can
|
|
1662
|
+
* be called unconditionally from the CLI's start path.
|
|
1663
|
+
*/
|
|
1664
|
+
needsRepair(): {
|
|
1665
|
+
reason: string;
|
|
1666
|
+
} | null;
|
|
1622
1667
|
}
|
|
1623
1668
|
|
|
1624
1669
|
interface SetupConfig {
|
package/dist/index.js
CHANGED
|
@@ -484,7 +484,8 @@ var InboxWatcher = class extends EventEmitter {
|
|
|
484
484
|
this.emit("close");
|
|
485
485
|
this._scheduleReconnect();
|
|
486
486
|
});
|
|
487
|
-
|
|
487
|
+
lock.release();
|
|
488
|
+
this._lock = null;
|
|
488
489
|
} catch (err) {
|
|
489
490
|
lock.release();
|
|
490
491
|
throw err;
|
|
@@ -1163,7 +1164,15 @@ var AccountManager = class {
|
|
|
1163
1164
|
}
|
|
1164
1165
|
const principalName = options.name.toLowerCase();
|
|
1165
1166
|
const email = `${principalName}@${domain}`;
|
|
1167
|
+
const existingAgent = await this.getByName(options.name);
|
|
1168
|
+
if (existingAgent != null) {
|
|
1169
|
+
throw new Error(`Account already exists: ${options.name}`);
|
|
1170
|
+
}
|
|
1166
1171
|
await this.stalwart.ensureDomain(domain);
|
|
1172
|
+
try {
|
|
1173
|
+
await this.stalwart.deletePrincipal(principalName);
|
|
1174
|
+
} catch {
|
|
1175
|
+
}
|
|
1167
1176
|
await this.stalwart.createPrincipal({
|
|
1168
1177
|
type: "individual",
|
|
1169
1178
|
name: principalName,
|
|
@@ -6310,6 +6319,7 @@ import { execFileSync as execFileSync3, execSync as execSync2 } from "child_proc
|
|
|
6310
6319
|
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync5, chmodSync } from "fs";
|
|
6311
6320
|
import { join as join8 } from "path";
|
|
6312
6321
|
import { homedir as homedir7, platform as platform4 } from "os";
|
|
6322
|
+
import { createRequire } from "module";
|
|
6313
6323
|
var PLIST_LABEL = "com.agenticmail.server";
|
|
6314
6324
|
var SYSTEMD_UNIT = "agenticmail.service";
|
|
6315
6325
|
var ServiceManager = class {
|
|
@@ -6336,42 +6346,59 @@ var ServiceManager = class {
|
|
|
6336
6346
|
}
|
|
6337
6347
|
/**
|
|
6338
6348
|
* Find the API server entry point.
|
|
6339
|
-
*
|
|
6349
|
+
*
|
|
6350
|
+
* Issue #26 — Robust path resolution.
|
|
6351
|
+
*
|
|
6352
|
+
* The original implementation hard-coded `node_modules/agenticmail` (the
|
|
6353
|
+
* old unscoped package name). After the rename to `@agenticmail/cli`, that
|
|
6354
|
+
* directory no longer exists, so the resolver fell back to the stale
|
|
6355
|
+
* `~/.agenticmail/api-entry.path` cache and the launchd plist kept pointing
|
|
6356
|
+
* at a deleted path — causing the boot crash loop reported in #26.
|
|
6357
|
+
*
|
|
6358
|
+
* We now prefer `require.resolve('@agenticmail/api')` so the resolution
|
|
6359
|
+
* follows the actual installed location regardless of npm prefix, the
|
|
6360
|
+
* scoped vs unscoped package name, or the package manager (npm global,
|
|
6361
|
+
* pnpm, yarn global, local node_modules). Cached paths are always
|
|
6362
|
+
* validated against the filesystem before being returned.
|
|
6340
6363
|
*/
|
|
6341
6364
|
getApiEntryPath() {
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
} catch {
|
|
6354
|
-
return [];
|
|
6355
|
-
}
|
|
6356
|
-
})(),
|
|
6357
|
-
// Homebrew on macOS
|
|
6358
|
-
"/opt/homebrew/lib/node_modules/agenticmail",
|
|
6359
|
-
"/usr/local/lib/node_modules/agenticmail"
|
|
6365
|
+
try {
|
|
6366
|
+
const req = createRequire(import.meta.url);
|
|
6367
|
+
const resolved = req.resolve("@agenticmail/api");
|
|
6368
|
+
if (existsSync6(resolved)) return resolved;
|
|
6369
|
+
} catch {
|
|
6370
|
+
}
|
|
6371
|
+
const parentPackages = [
|
|
6372
|
+
join8("@agenticmail", "cli"),
|
|
6373
|
+
// current scoped package
|
|
6374
|
+
"agenticmail"
|
|
6375
|
+
// legacy unscoped package
|
|
6360
6376
|
];
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6377
|
+
const baseDirs = [
|
|
6378
|
+
// user-local install
|
|
6379
|
+
join8(homedir7(), "node_modules")
|
|
6380
|
+
];
|
|
6381
|
+
try {
|
|
6382
|
+
const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
6383
|
+
baseDirs.push(join8(prefix, "lib", "node_modules"));
|
|
6384
|
+
baseDirs.push(join8(prefix, "node_modules"));
|
|
6385
|
+
} catch {
|
|
6386
|
+
}
|
|
6387
|
+
baseDirs.push("/opt/homebrew/lib/node_modules");
|
|
6388
|
+
baseDirs.push("/usr/local/lib/node_modules");
|
|
6389
|
+
for (const base of baseDirs) {
|
|
6390
|
+
const sibling = join8(base, "@agenticmail", "api", "dist", "index.js");
|
|
6391
|
+
if (existsSync6(sibling)) return sibling;
|
|
6392
|
+
for (const parent of parentPackages) {
|
|
6393
|
+
const nested = join8(base, parent, "node_modules", "@agenticmail", "api", "dist", "index.js");
|
|
6394
|
+
if (existsSync6(nested)) return nested;
|
|
6368
6395
|
}
|
|
6369
6396
|
}
|
|
6370
6397
|
const dataDir = join8(homedir7(), ".agenticmail");
|
|
6371
6398
|
const entryCache = join8(dataDir, "api-entry.path");
|
|
6372
6399
|
if (existsSync6(entryCache)) {
|
|
6373
6400
|
const cached = readFileSync3(entryCache, "utf-8").trim();
|
|
6374
|
-
if (existsSync6(cached)) return cached;
|
|
6401
|
+
if (cached && existsSync6(cached)) return cached;
|
|
6375
6402
|
}
|
|
6376
6403
|
throw new Error("Could not find @agenticmail/api entry point. Run `agenticmail start` first to populate the cache.");
|
|
6377
6404
|
}
|
|
@@ -6385,25 +6412,49 @@ var ServiceManager = class {
|
|
|
6385
6412
|
}
|
|
6386
6413
|
/**
|
|
6387
6414
|
* Get the current package version.
|
|
6415
|
+
*
|
|
6416
|
+
* Issue #26 — resolve the CLI package.json via require.resolve so the
|
|
6417
|
+
* version reflects the *currently installed* @agenticmail/cli, not a
|
|
6418
|
+
* leftover unscoped `agenticmail` package directory.
|
|
6388
6419
|
*/
|
|
6389
6420
|
getVersion() {
|
|
6390
6421
|
try {
|
|
6391
|
-
const
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
6397
|
-
pkgPaths.push(join8(prefix, "lib", "node_modules", "agenticmail", "package.json"));
|
|
6398
|
-
} catch {
|
|
6422
|
+
const req = createRequire(import.meta.url);
|
|
6423
|
+
const pkgJson = req.resolve("@agenticmail/cli/package.json");
|
|
6424
|
+
if (existsSync6(pkgJson)) {
|
|
6425
|
+
const pkg = JSON.parse(readFileSync3(pkgJson, "utf-8"));
|
|
6426
|
+
if (pkg.version) return pkg.version;
|
|
6399
6427
|
}
|
|
6400
|
-
|
|
6428
|
+
} catch {
|
|
6429
|
+
}
|
|
6430
|
+
try {
|
|
6431
|
+
const apiEntry = this.getApiEntryPath();
|
|
6432
|
+
const apiPkg = join8(apiEntry, "..", "..", "package.json");
|
|
6433
|
+
if (existsSync6(apiPkg)) {
|
|
6434
|
+
const pkg = JSON.parse(readFileSync3(apiPkg, "utf-8"));
|
|
6435
|
+
if (pkg.version) return pkg.version;
|
|
6436
|
+
}
|
|
6437
|
+
} catch {
|
|
6438
|
+
}
|
|
6439
|
+
const candidates = [
|
|
6440
|
+
join8(homedir7(), "node_modules", "@agenticmail", "cli", "package.json"),
|
|
6441
|
+
join8(homedir7(), "node_modules", "agenticmail", "package.json"),
|
|
6442
|
+
join8(homedir7(), ".agenticmail", "package-version.json")
|
|
6443
|
+
];
|
|
6444
|
+
try {
|
|
6445
|
+
const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
6446
|
+
candidates.push(join8(prefix, "lib", "node_modules", "@agenticmail", "cli", "package.json"));
|
|
6447
|
+
candidates.push(join8(prefix, "lib", "node_modules", "agenticmail", "package.json"));
|
|
6448
|
+
} catch {
|
|
6449
|
+
}
|
|
6450
|
+
for (const p of candidates) {
|
|
6451
|
+
try {
|
|
6401
6452
|
if (existsSync6(p)) {
|
|
6402
6453
|
const pkg = JSON.parse(readFileSync3(p, "utf-8"));
|
|
6403
6454
|
if (pkg.version) return pkg.version;
|
|
6404
6455
|
}
|
|
6456
|
+
} catch {
|
|
6405
6457
|
}
|
|
6406
|
-
} catch {
|
|
6407
6458
|
}
|
|
6408
6459
|
return "unknown";
|
|
6409
6460
|
}
|
|
@@ -6709,6 +6760,86 @@ WantedBy=default.target
|
|
|
6709
6760
|
this.uninstall();
|
|
6710
6761
|
return this.install();
|
|
6711
6762
|
}
|
|
6763
|
+
/**
|
|
6764
|
+
* Issue #26 — Detect a stale service installation.
|
|
6765
|
+
*
|
|
6766
|
+
* Background: when a user upgrades from the old unscoped `agenticmail`
|
|
6767
|
+
* package to the new `@agenticmail/cli` scoped package, the old
|
|
6768
|
+
* ~/Library/LaunchAgents/com.agenticmail.server.plist and
|
|
6769
|
+
* ~/.agenticmail/bin/start-server.sh files keep pointing at
|
|
6770
|
+
* /opt/homebrew/lib/node_modules/agenticmail/... — a path that no longer
|
|
6771
|
+
* exists post-rename. The result is a launchd crash loop.
|
|
6772
|
+
*
|
|
6773
|
+
* `needsRepair()` returns a non-null reason whenever:
|
|
6774
|
+
* - the service file exists but the start-server.sh it launches is
|
|
6775
|
+
* missing or references a node_modules path that no longer resolves;
|
|
6776
|
+
* - the embedded service version drifts from the running CLI version
|
|
6777
|
+
* (so service files get refreshed on every upgrade — including
|
|
6778
|
+
* in-place version bumps that don't change the install path);
|
|
6779
|
+
* - the cached API entry path no longer exists on disk.
|
|
6780
|
+
*
|
|
6781
|
+
* Returns null when everything checks out — callers should treat that as
|
|
6782
|
+
* "no action needed".
|
|
6783
|
+
*
|
|
6784
|
+
* Platform-aware: only inspects launchd artefacts on darwin and systemd
|
|
6785
|
+
* artefacts on linux. Returns null on unsupported platforms so this can
|
|
6786
|
+
* be called unconditionally from the CLI's start path.
|
|
6787
|
+
*/
|
|
6788
|
+
needsRepair() {
|
|
6789
|
+
if (this.os !== "darwin" && this.os !== "linux") return null;
|
|
6790
|
+
const servicePath = this.getServicePath();
|
|
6791
|
+
if (!existsSync6(servicePath)) return null;
|
|
6792
|
+
let serviceContent = "";
|
|
6793
|
+
try {
|
|
6794
|
+
serviceContent = readFileSync3(servicePath, "utf-8");
|
|
6795
|
+
} catch {
|
|
6796
|
+
return { reason: "Service file unreadable" };
|
|
6797
|
+
}
|
|
6798
|
+
const startScript = join8(homedir7(), ".agenticmail", "bin", "start-server.sh");
|
|
6799
|
+
if (serviceContent.includes(startScript)) {
|
|
6800
|
+
if (!existsSync6(startScript)) {
|
|
6801
|
+
return { reason: "start-server.sh is missing" };
|
|
6802
|
+
}
|
|
6803
|
+
let scriptContent = "";
|
|
6804
|
+
try {
|
|
6805
|
+
scriptContent = readFileSync3(startScript, "utf-8");
|
|
6806
|
+
} catch {
|
|
6807
|
+
return { reason: "start-server.sh unreadable" };
|
|
6808
|
+
}
|
|
6809
|
+
const apiPathMatch = scriptContent.match(/(\/[^"\s]+@agenticmail\/api\/dist\/index\.js)/);
|
|
6810
|
+
if (apiPathMatch) {
|
|
6811
|
+
const referenced = apiPathMatch[1];
|
|
6812
|
+
if (!existsSync6(referenced)) {
|
|
6813
|
+
return { reason: `start-server.sh references missing path: ${referenced}` };
|
|
6814
|
+
}
|
|
6815
|
+
}
|
|
6816
|
+
if (/node_modules\/agenticmail\/(?!.*@agenticmail\/cli)/.test(scriptContent)) {
|
|
6817
|
+
const stale = /(\S*node_modules\/agenticmail\/\S*)/.exec(scriptContent)?.[1];
|
|
6818
|
+
if (stale && !existsSync6(stale)) {
|
|
6819
|
+
return { reason: `start-server.sh references legacy unscoped path: ${stale}` };
|
|
6820
|
+
}
|
|
6821
|
+
}
|
|
6822
|
+
} else {
|
|
6823
|
+
return { reason: "Service file does not reference the wrapper script" };
|
|
6824
|
+
}
|
|
6825
|
+
const currentVersion = this.getVersion();
|
|
6826
|
+
if (currentVersion !== "unknown") {
|
|
6827
|
+
if (!serviceContent.includes(`v${currentVersion}`) || !serviceContent.includes(`AGENTICMAIL_SERVICE_VERSION`) || !serviceContent.includes(currentVersion)) {
|
|
6828
|
+
return { reason: `Service version drift (current CLI is v${currentVersion})` };
|
|
6829
|
+
}
|
|
6830
|
+
}
|
|
6831
|
+
const entryCache = join8(homedir7(), ".agenticmail", "api-entry.path");
|
|
6832
|
+
if (existsSync6(entryCache)) {
|
|
6833
|
+
try {
|
|
6834
|
+
const cached = readFileSync3(entryCache, "utf-8").trim();
|
|
6835
|
+
if (cached && !existsSync6(cached)) {
|
|
6836
|
+
return { reason: `Cached API entry path no longer exists: ${cached}` };
|
|
6837
|
+
}
|
|
6838
|
+
} catch {
|
|
6839
|
+
}
|
|
6840
|
+
}
|
|
6841
|
+
return null;
|
|
6842
|
+
}
|
|
6712
6843
|
};
|
|
6713
6844
|
|
|
6714
6845
|
// src/setup/index.ts
|