@agenticmail/core 0.5.8 → 0.5.10
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.d.ts +14 -0
- package/dist/index.js +77 -24
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1439,6 +1439,20 @@ declare class DependencyInstaller {
|
|
|
1439
1439
|
* Validates symlinks aren't broken.
|
|
1440
1440
|
*/
|
|
1441
1441
|
private findDockerApp;
|
|
1442
|
+
/**
|
|
1443
|
+
* Pre-accept the Docker Desktop license agreement by writing the settings
|
|
1444
|
+
* file that Docker checks on startup. This prevents the license dialog from
|
|
1445
|
+
* appearing and blocking automated setup.
|
|
1446
|
+
*
|
|
1447
|
+
* Docker Desktop checks /Library/Application Support/com.docker.docker/install-settings.json
|
|
1448
|
+
* (system-level, requires sudo) for {"acceptLicense": true}. The --accept-license
|
|
1449
|
+
* flag on the installer binary tries to write this but fails without sudo.
|
|
1450
|
+
*
|
|
1451
|
+
* We try multiple approaches:
|
|
1452
|
+
* 1. Write to the system-level path (may fail without sudo — that's OK)
|
|
1453
|
+
* 2. Write to the user-level Docker settings (Group Containers)
|
|
1454
|
+
*/
|
|
1455
|
+
private preAcceptDockerLicense;
|
|
1442
1456
|
/**
|
|
1443
1457
|
* Docker.app exists but CLI isn't available or daemon isn't running.
|
|
1444
1458
|
* Runs the built-in installer silently (--accept-license to link CLI tools),
|
package/dist/index.js
CHANGED
|
@@ -850,14 +850,14 @@ var StalwartAdmin = class {
|
|
|
850
850
|
* Critical for email deliverability — must match the sending domain.
|
|
851
851
|
*/
|
|
852
852
|
async setHostname(domain) {
|
|
853
|
-
const { readFileSync:
|
|
853
|
+
const { readFileSync: readFileSync5, writeFileSync: writeFileSync6 } = await import("fs");
|
|
854
854
|
const { homedir: homedir8 } = await import("os");
|
|
855
855
|
const { join: join9 } = await import("path");
|
|
856
856
|
const configPath = join9(homedir8(), ".agenticmail", "stalwart.toml");
|
|
857
857
|
try {
|
|
858
|
-
let config =
|
|
858
|
+
let config = readFileSync5(configPath, "utf-8");
|
|
859
859
|
config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${domain}"`);
|
|
860
|
-
|
|
860
|
+
writeFileSync6(configPath, config);
|
|
861
861
|
console.log(`[Stalwart] Updated hostname to "${domain}" in stalwart.toml`);
|
|
862
862
|
} catch (err) {
|
|
863
863
|
throw new Error(`Failed to set config server.hostname=${domain}`);
|
|
@@ -975,12 +975,12 @@ var StalwartAdmin = class {
|
|
|
975
975
|
* This bypasses the need for a PTR record on the sending IP.
|
|
976
976
|
*/
|
|
977
977
|
async configureOutboundRelay(config) {
|
|
978
|
-
const { readFileSync:
|
|
978
|
+
const { readFileSync: readFileSync5, writeFileSync: writeFileSync6 } = await import("fs");
|
|
979
979
|
const { homedir: homedir8 } = await import("os");
|
|
980
980
|
const { join: join9 } = await import("path");
|
|
981
981
|
const routeName = config.routeName ?? "gmail";
|
|
982
982
|
const tomlPath = join9(homedir8(), ".agenticmail", "stalwart.toml");
|
|
983
|
-
let toml =
|
|
983
|
+
let toml = readFileSync5(tomlPath, "utf-8");
|
|
984
984
|
toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
|
|
985
985
|
toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
|
|
986
986
|
toml += `
|
|
@@ -999,7 +999,7 @@ auth.secret = "${config.password}"
|
|
|
999
999
|
route = [ { if = "is_local_domain('', rcpt_domain)", then = "'local'" },
|
|
1000
1000
|
{ else = "'${routeName}'" } ]
|
|
1001
1001
|
`;
|
|
1002
|
-
|
|
1002
|
+
writeFileSync6(tomlPath, toml, "utf-8");
|
|
1003
1003
|
await this.restartContainer();
|
|
1004
1004
|
}
|
|
1005
1005
|
};
|
|
@@ -5180,9 +5180,9 @@ var GatewayManager = class {
|
|
|
5180
5180
|
const { homedir: homedir8 } = await import("os");
|
|
5181
5181
|
const backupDir = join4(homedir8(), ".agenticmail");
|
|
5182
5182
|
const backupPath = join4(backupDir, `dns-backup-${domain}-${Date.now()}.json`);
|
|
5183
|
-
const { writeFileSync:
|
|
5183
|
+
const { writeFileSync: writeFileSync6, mkdirSync: mkdirSync5 } = await import("fs");
|
|
5184
5184
|
mkdirSync5(backupDir, { recursive: true });
|
|
5185
|
-
|
|
5185
|
+
writeFileSync6(backupPath, JSON.stringify({
|
|
5186
5186
|
domain,
|
|
5187
5187
|
zoneId: zone.id,
|
|
5188
5188
|
backedUpAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -5813,7 +5813,7 @@ var RELAY_PRESETS = {
|
|
|
5813
5813
|
|
|
5814
5814
|
// src/setup/index.ts
|
|
5815
5815
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
5816
|
-
import { existsSync as existsSync6, readFileSync as
|
|
5816
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, chmodSync } from "fs";
|
|
5817
5817
|
import { join as join8 } from "path";
|
|
5818
5818
|
import { homedir as homedir7 } from "os";
|
|
5819
5819
|
|
|
@@ -5894,7 +5894,7 @@ var DependencyChecker = class {
|
|
|
5894
5894
|
|
|
5895
5895
|
// src/setup/installer.ts
|
|
5896
5896
|
import { execFileSync as execFileSync2, execSync, spawn as spawnChild } from "child_process";
|
|
5897
|
-
import { existsSync as existsSync4, readdirSync, lstatSync, readlinkSync } from "fs";
|
|
5897
|
+
import { existsSync as existsSync4, readdirSync, lstatSync, readlinkSync, writeFileSync as writeFileSync3, readFileSync as readFileSync2 } from "fs";
|
|
5898
5898
|
import { writeFile, rename, chmod as chmod2, mkdir as mkdir2, unlink } from "fs/promises";
|
|
5899
5899
|
import { join as join6 } from "path";
|
|
5900
5900
|
import { homedir as homedir5, platform as platform2, arch as arch2 } from "os";
|
|
@@ -6149,6 +6149,57 @@ var DependencyInstaller = class {
|
|
|
6149
6149
|
}
|
|
6150
6150
|
return null;
|
|
6151
6151
|
}
|
|
6152
|
+
/**
|
|
6153
|
+
* Pre-accept the Docker Desktop license agreement by writing the settings
|
|
6154
|
+
* file that Docker checks on startup. This prevents the license dialog from
|
|
6155
|
+
* appearing and blocking automated setup.
|
|
6156
|
+
*
|
|
6157
|
+
* Docker Desktop checks /Library/Application Support/com.docker.docker/install-settings.json
|
|
6158
|
+
* (system-level, requires sudo) for {"acceptLicense": true}. The --accept-license
|
|
6159
|
+
* flag on the installer binary tries to write this but fails without sudo.
|
|
6160
|
+
*
|
|
6161
|
+
* We try multiple approaches:
|
|
6162
|
+
* 1. Write to the system-level path (may fail without sudo — that's OK)
|
|
6163
|
+
* 2. Write to the user-level Docker settings (Group Containers)
|
|
6164
|
+
*/
|
|
6165
|
+
preAcceptDockerLicense() {
|
|
6166
|
+
const systemDir = "/Library/Application Support/com.docker.docker";
|
|
6167
|
+
const systemFile = join6(systemDir, "install-settings.json");
|
|
6168
|
+
const licenseJson = JSON.stringify({ acceptLicense: true });
|
|
6169
|
+
try {
|
|
6170
|
+
if (!existsSync4(systemDir)) {
|
|
6171
|
+
execSync(`mkdir -p "${systemDir}"`, { timeout: 5e3, stdio: "ignore" });
|
|
6172
|
+
}
|
|
6173
|
+
writeFileSync3(systemFile, licenseJson, { mode: 420 });
|
|
6174
|
+
} catch {
|
|
6175
|
+
try {
|
|
6176
|
+
execSync(`sudo -n mkdir -p "${systemDir}" 2>/dev/null && sudo -n tee "${systemFile}" > /dev/null 2>&1`, {
|
|
6177
|
+
timeout: 5e3,
|
|
6178
|
+
input: licenseJson,
|
|
6179
|
+
stdio: ["pipe", "ignore", "ignore"]
|
|
6180
|
+
});
|
|
6181
|
+
} catch {
|
|
6182
|
+
}
|
|
6183
|
+
}
|
|
6184
|
+
try {
|
|
6185
|
+
const userDockerDir = join6(process.env.HOME || "", "Library/Group Containers/group.com.docker");
|
|
6186
|
+
const settingsFile = join6(userDockerDir, "settings-store.json");
|
|
6187
|
+
if (existsSync4(settingsFile)) {
|
|
6188
|
+
const raw = readFileSync2(settingsFile, "utf-8");
|
|
6189
|
+
try {
|
|
6190
|
+
const settings = JSON.parse(raw);
|
|
6191
|
+
if (!settings.AcceptedLicense) {
|
|
6192
|
+
settings.AcceptedLicense = true;
|
|
6193
|
+
writeFileSync3(settingsFile, JSON.stringify(settings, null, 2));
|
|
6194
|
+
}
|
|
6195
|
+
} catch {
|
|
6196
|
+
}
|
|
6197
|
+
} else if (existsSync4(userDockerDir)) {
|
|
6198
|
+
writeFileSync3(settingsFile, JSON.stringify({ AcceptedLicense: true }, null, 2));
|
|
6199
|
+
}
|
|
6200
|
+
} catch {
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
6152
6203
|
/**
|
|
6153
6204
|
* Docker.app exists but CLI isn't available or daemon isn't running.
|
|
6154
6205
|
* Runs the built-in installer silently (--accept-license to link CLI tools),
|
|
@@ -6156,6 +6207,7 @@ var DependencyInstaller = class {
|
|
|
6156
6207
|
*/
|
|
6157
6208
|
async setupExistingDockerApp(appPath) {
|
|
6158
6209
|
const installBin = join6(appPath, "Contents", "MacOS", "install");
|
|
6210
|
+
this.preAcceptDockerLicense();
|
|
6159
6211
|
if (existsSync4(installBin)) {
|
|
6160
6212
|
this.onProgress("__progress__:30:Setting up Docker CLI tools...");
|
|
6161
6213
|
const user = process.env.USER || execSync("whoami", { timeout: 5e3 }).toString().trim();
|
|
@@ -6249,6 +6301,7 @@ var DependencyInstaller = class {
|
|
|
6249
6301
|
} catch {
|
|
6250
6302
|
throw new Error("Failed to mount Docker DMG. The download may be corrupted \u2014 try again.");
|
|
6251
6303
|
}
|
|
6304
|
+
this.preAcceptDockerLicense();
|
|
6252
6305
|
this.onProgress("__progress__:55:Running Docker installer...");
|
|
6253
6306
|
const user = process.env.USER || execSync("whoami", { timeout: 5e3 }).toString().trim();
|
|
6254
6307
|
try {
|
|
@@ -6580,7 +6633,7 @@ var DependencyInstaller = class {
|
|
|
6580
6633
|
|
|
6581
6634
|
// src/setup/service.ts
|
|
6582
6635
|
import { execFileSync as execFileSync3, execSync as execSync2 } from "child_process";
|
|
6583
|
-
import { existsSync as existsSync5, readFileSync as
|
|
6636
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
|
|
6584
6637
|
import { join as join7 } from "path";
|
|
6585
6638
|
import { homedir as homedir6, platform as platform3 } from "os";
|
|
6586
6639
|
var PLIST_LABEL = "com.agenticmail.server";
|
|
@@ -6643,7 +6696,7 @@ var ServiceManager = class {
|
|
|
6643
6696
|
const dataDir = join7(homedir6(), ".agenticmail");
|
|
6644
6697
|
const entryCache = join7(dataDir, "api-entry.path");
|
|
6645
6698
|
if (existsSync5(entryCache)) {
|
|
6646
|
-
const cached =
|
|
6699
|
+
const cached = readFileSync3(entryCache, "utf-8").trim();
|
|
6647
6700
|
if (existsSync5(cached)) return cached;
|
|
6648
6701
|
}
|
|
6649
6702
|
throw new Error("Could not find @agenticmail/api entry point. Run `agenticmail start` first to populate the cache.");
|
|
@@ -6654,7 +6707,7 @@ var ServiceManager = class {
|
|
|
6654
6707
|
cacheApiEntryPath(entryPath) {
|
|
6655
6708
|
const dataDir = join7(homedir6(), ".agenticmail");
|
|
6656
6709
|
if (!existsSync5(dataDir)) mkdirSync3(dataDir, { recursive: true });
|
|
6657
|
-
|
|
6710
|
+
writeFileSync4(join7(dataDir, "api-entry.path"), entryPath);
|
|
6658
6711
|
}
|
|
6659
6712
|
/**
|
|
6660
6713
|
* Get the current package version.
|
|
@@ -6672,7 +6725,7 @@ var ServiceManager = class {
|
|
|
6672
6725
|
}
|
|
6673
6726
|
for (const p of pkgPaths) {
|
|
6674
6727
|
if (existsSync5(p)) {
|
|
6675
|
-
const pkg = JSON.parse(
|
|
6728
|
+
const pkg = JSON.parse(readFileSync3(p, "utf-8"));
|
|
6676
6729
|
if (pkg.version) return pkg.version;
|
|
6677
6730
|
}
|
|
6678
6731
|
}
|
|
@@ -6738,7 +6791,7 @@ var ServiceManager = class {
|
|
|
6738
6791
|
`log "Starting API server: ${nodePath} ${apiEntry}"`,
|
|
6739
6792
|
`exec "${nodePath}" "${apiEntry}"`
|
|
6740
6793
|
].join("\n") + "\n";
|
|
6741
|
-
|
|
6794
|
+
writeFileSync4(scriptPath, script, { mode: 493 });
|
|
6742
6795
|
return scriptPath;
|
|
6743
6796
|
}
|
|
6744
6797
|
/**
|
|
@@ -6751,7 +6804,7 @@ var ServiceManager = class {
|
|
|
6751
6804
|
* - Service version tracking in env vars
|
|
6752
6805
|
*/
|
|
6753
6806
|
generatePlist(nodePath, apiEntry, configPath) {
|
|
6754
|
-
const config = JSON.parse(
|
|
6807
|
+
const config = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
6755
6808
|
const logDir = join7(homedir6(), ".agenticmail", "logs");
|
|
6756
6809
|
if (!existsSync5(logDir)) mkdirSync3(logDir, { recursive: true });
|
|
6757
6810
|
const version = this.getVersion();
|
|
@@ -6849,7 +6902,7 @@ var ServiceManager = class {
|
|
|
6849
6902
|
* - Proper dependency ordering
|
|
6850
6903
|
*/
|
|
6851
6904
|
generateSystemdUnit(nodePath, apiEntry, configPath) {
|
|
6852
|
-
const config = JSON.parse(
|
|
6905
|
+
const config = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
6853
6906
|
const dataDir = config.dataDir || join7(homedir6(), ".agenticmail");
|
|
6854
6907
|
const version = this.getVersion();
|
|
6855
6908
|
const startScript = this.generateStartScript(nodePath, apiEntry);
|
|
@@ -6912,7 +6965,7 @@ WantedBy=default.target
|
|
|
6912
6965
|
}
|
|
6913
6966
|
}
|
|
6914
6967
|
const plist = this.generatePlist(nodePath, apiEntry, configPath);
|
|
6915
|
-
|
|
6968
|
+
writeFileSync4(servicePath, plist);
|
|
6916
6969
|
try {
|
|
6917
6970
|
execFileSync3("launchctl", ["load", servicePath], { timeout: 1e4, stdio: "ignore" });
|
|
6918
6971
|
} catch (err) {
|
|
@@ -6923,7 +6976,7 @@ WantedBy=default.target
|
|
|
6923
6976
|
const dir = join7(homedir6(), ".config", "systemd", "user");
|
|
6924
6977
|
if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
|
|
6925
6978
|
const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
|
|
6926
|
-
|
|
6979
|
+
writeFileSync4(servicePath, unit);
|
|
6927
6980
|
try {
|
|
6928
6981
|
execFileSync3("systemctl", ["--user", "daemon-reload"], { timeout: 1e4, stdio: "ignore" });
|
|
6929
6982
|
execFileSync3("systemctl", ["--user", "enable", SYSTEMD_UNIT], { timeout: 1e4, stdio: "ignore" });
|
|
@@ -7074,7 +7127,7 @@ var SetupManager = class {
|
|
|
7074
7127
|
const envPath = join8(dataDir, ".env");
|
|
7075
7128
|
if (existsSync6(configPath)) {
|
|
7076
7129
|
try {
|
|
7077
|
-
const existing = JSON.parse(
|
|
7130
|
+
const existing = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
7078
7131
|
this.generateDockerFiles(existing);
|
|
7079
7132
|
return { configPath, envPath, config: existing, isNew: false };
|
|
7080
7133
|
} catch {
|
|
@@ -7097,7 +7150,7 @@ var SetupManager = class {
|
|
|
7097
7150
|
api: { port: 3100, host: "127.0.0.1" },
|
|
7098
7151
|
dataDir
|
|
7099
7152
|
};
|
|
7100
|
-
|
|
7153
|
+
writeFileSync5(configPath, JSON.stringify(config, null, 2));
|
|
7101
7154
|
chmodSync(configPath, 384);
|
|
7102
7155
|
const envContent = `# Auto-generated by agenticmail setup
|
|
7103
7156
|
STALWART_ADMIN_USER=admin
|
|
@@ -7113,7 +7166,7 @@ SMTP_PORT=587
|
|
|
7113
7166
|
IMAP_HOST=localhost
|
|
7114
7167
|
IMAP_PORT=143
|
|
7115
7168
|
`;
|
|
7116
|
-
|
|
7169
|
+
writeFileSync5(envPath, envContent);
|
|
7117
7170
|
chmodSync(envPath, 384);
|
|
7118
7171
|
this.generateDockerFiles(config);
|
|
7119
7172
|
return { configPath, envPath, config, isNew: true };
|
|
@@ -7129,7 +7182,7 @@ IMAP_PORT=143
|
|
|
7129
7182
|
}
|
|
7130
7183
|
const password = config.stalwart?.adminPassword || "changeme";
|
|
7131
7184
|
const composePath = join8(dataDir, "docker-compose.yml");
|
|
7132
|
-
|
|
7185
|
+
writeFileSync5(composePath, `services:
|
|
7133
7186
|
stalwart:
|
|
7134
7187
|
image: stalwartlabs/stalwart:latest
|
|
7135
7188
|
container_name: agenticmail-stalwart
|
|
@@ -7152,7 +7205,7 @@ volumes:
|
|
|
7152
7205
|
stalwart-data:
|
|
7153
7206
|
`);
|
|
7154
7207
|
const tomlPath = join8(dataDir, "stalwart.toml");
|
|
7155
|
-
|
|
7208
|
+
writeFileSync5(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
|
|
7156
7209
|
|
|
7157
7210
|
[server]
|
|
7158
7211
|
hostname = "localhost"
|