@agenticmail/core 0.5.7 → 0.5.9
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 +24 -3
- package/dist/index.js +159 -63
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1440,13 +1440,34 @@ declare class DependencyInstaller {
|
|
|
1440
1440
|
*/
|
|
1441
1441
|
private findDockerApp;
|
|
1442
1442
|
/**
|
|
1443
|
-
* Docker
|
|
1444
|
-
*
|
|
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;
|
|
1456
|
+
/**
|
|
1457
|
+
* Docker.app exists but CLI isn't available or daemon isn't running.
|
|
1458
|
+
* Runs the built-in installer silently (--accept-license to link CLI tools),
|
|
1459
|
+
* then starts Docker Desktop hidden (no GUI window).
|
|
1445
1460
|
*/
|
|
1446
1461
|
private setupExistingDockerApp;
|
|
1462
|
+
/**
|
|
1463
|
+
* Hide the Docker Desktop window using AppleScript.
|
|
1464
|
+
* Called after starting Docker to suppress the welcome/dashboard GUI.
|
|
1465
|
+
*/
|
|
1466
|
+
private hideDockerWindow;
|
|
1447
1467
|
/**
|
|
1448
1468
|
* Full Docker Desktop install on macOS.
|
|
1449
|
-
* Tries Homebrew first (cleaner
|
|
1469
|
+
* Tries Homebrew first (cleaner), falls back to DMG download.
|
|
1470
|
+
* All output is suppressed — only our progress spinner shows.
|
|
1450
1471
|
*/
|
|
1451
1472
|
private installDockerMac;
|
|
1452
1473
|
/**
|
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";
|
|
@@ -6016,6 +6016,24 @@ function runShellWithRollingOutput(cmd, opts = {}) {
|
|
|
6016
6016
|
});
|
|
6017
6017
|
});
|
|
6018
6018
|
}
|
|
6019
|
+
function runSilent(command, args, opts = {}) {
|
|
6020
|
+
const timeout = opts.timeout ?? 3e5;
|
|
6021
|
+
return new Promise((resolve, reject) => {
|
|
6022
|
+
const child = spawnChild(command, args, {
|
|
6023
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
6024
|
+
timeout
|
|
6025
|
+
});
|
|
6026
|
+
let fullOutput = "";
|
|
6027
|
+
child.stdout?.on("data", (d) => {
|
|
6028
|
+
fullOutput += d.toString();
|
|
6029
|
+
});
|
|
6030
|
+
child.stderr?.on("data", (d) => {
|
|
6031
|
+
fullOutput += d.toString();
|
|
6032
|
+
});
|
|
6033
|
+
child.on("close", (code) => resolve({ exitCode: code ?? 1, fullOutput }));
|
|
6034
|
+
child.on("error", reject);
|
|
6035
|
+
});
|
|
6036
|
+
}
|
|
6019
6037
|
function existsReal(p) {
|
|
6020
6038
|
try {
|
|
6021
6039
|
const stat = lstatSync(p);
|
|
@@ -6132,56 +6150,140 @@ var DependencyInstaller = class {
|
|
|
6132
6150
|
return null;
|
|
6133
6151
|
}
|
|
6134
6152
|
/**
|
|
6135
|
-
* Docker
|
|
6136
|
-
*
|
|
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
|
+
}
|
|
6203
|
+
/**
|
|
6204
|
+
* Docker.app exists but CLI isn't available or daemon isn't running.
|
|
6205
|
+
* Runs the built-in installer silently (--accept-license to link CLI tools),
|
|
6206
|
+
* then starts Docker Desktop hidden (no GUI window).
|
|
6137
6207
|
*/
|
|
6138
6208
|
async setupExistingDockerApp(appPath) {
|
|
6139
6209
|
const installBin = join6(appPath, "Contents", "MacOS", "install");
|
|
6210
|
+
this.preAcceptDockerLicense();
|
|
6140
6211
|
if (existsSync4(installBin)) {
|
|
6141
|
-
this.onProgress("__progress__:
|
|
6212
|
+
this.onProgress("__progress__:30:Setting up Docker CLI tools...");
|
|
6142
6213
|
const user = process.env.USER || execSync("whoami", { timeout: 5e3 }).toString().trim();
|
|
6143
6214
|
try {
|
|
6144
|
-
|
|
6145
|
-
timeout: 12e4
|
|
6215
|
+
execSync(`"${installBin}" --accept-license --user=${user}`, {
|
|
6216
|
+
timeout: 12e4,
|
|
6217
|
+
stdio: "ignore"
|
|
6146
6218
|
});
|
|
6147
6219
|
} catch {
|
|
6148
6220
|
}
|
|
6149
6221
|
}
|
|
6150
|
-
this.onProgress("__progress__:
|
|
6222
|
+
this.onProgress("__progress__:50:Starting Docker engine...");
|
|
6151
6223
|
this.startDockerDaemon();
|
|
6224
|
+
this.hideDockerWindow();
|
|
6152
6225
|
await this.waitForDocker();
|
|
6153
6226
|
}
|
|
6227
|
+
/**
|
|
6228
|
+
* Hide the Docker Desktop window using AppleScript.
|
|
6229
|
+
* Called after starting Docker to suppress the welcome/dashboard GUI.
|
|
6230
|
+
*/
|
|
6231
|
+
hideDockerWindow() {
|
|
6232
|
+
try {
|
|
6233
|
+
execSync(
|
|
6234
|
+
`osascript -e 'tell application "System Events" to tell process "Docker Desktop" to set visible to false' 2>/dev/null`,
|
|
6235
|
+
{ timeout: 5e3, stdio: "ignore" }
|
|
6236
|
+
);
|
|
6237
|
+
} catch {
|
|
6238
|
+
}
|
|
6239
|
+
try {
|
|
6240
|
+
execSync(
|
|
6241
|
+
`osascript -e 'tell application "Docker Desktop" to close every window' 2>/dev/null`,
|
|
6242
|
+
{ timeout: 5e3, stdio: "ignore" }
|
|
6243
|
+
);
|
|
6244
|
+
} catch {
|
|
6245
|
+
}
|
|
6246
|
+
try {
|
|
6247
|
+
execSync(
|
|
6248
|
+
`osascript -e 'tell application "Docker" to close every window' 2>/dev/null`,
|
|
6249
|
+
{ timeout: 5e3, stdio: "ignore" }
|
|
6250
|
+
);
|
|
6251
|
+
} catch {
|
|
6252
|
+
}
|
|
6253
|
+
}
|
|
6154
6254
|
/**
|
|
6155
6255
|
* Full Docker Desktop install on macOS.
|
|
6156
|
-
* Tries Homebrew first (cleaner
|
|
6256
|
+
* Tries Homebrew first (cleaner), falls back to DMG download.
|
|
6257
|
+
* All output is suppressed — only our progress spinner shows.
|
|
6157
6258
|
*/
|
|
6158
6259
|
async installDockerMac() {
|
|
6159
6260
|
if (hasHomebrew()) {
|
|
6160
|
-
this.onProgress("__progress__:5:Installing Docker Desktop
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6261
|
+
this.onProgress("__progress__:5:Installing Docker Desktop...");
|
|
6262
|
+
try {
|
|
6263
|
+
const brewResult = await runSilent(
|
|
6264
|
+
"brew",
|
|
6265
|
+
["install", "--cask", "docker"],
|
|
6266
|
+
{ timeout: 6e5 }
|
|
6267
|
+
);
|
|
6268
|
+
if (brewResult.exitCode === 0) {
|
|
6269
|
+
this.onProgress("__progress__:45:Docker Desktop installed!");
|
|
6270
|
+
const appPath = this.findDockerApp();
|
|
6271
|
+
if (appPath) {
|
|
6272
|
+
await this.setupExistingDockerApp(appPath);
|
|
6273
|
+
return;
|
|
6274
|
+
}
|
|
6173
6275
|
}
|
|
6276
|
+
} catch {
|
|
6174
6277
|
}
|
|
6175
|
-
this.onProgress("__progress__:10:
|
|
6278
|
+
this.onProgress("__progress__:10:Trying direct download...");
|
|
6176
6279
|
}
|
|
6177
6280
|
const cpu = arch2();
|
|
6178
6281
|
const archName = cpu === "arm64" ? "arm64" : "amd64";
|
|
6179
6282
|
const dmgUrl = `https://desktop.docker.com/mac/main/${archName}/Docker.dmg`;
|
|
6180
6283
|
const dmgPath = "/tmp/Docker.dmg";
|
|
6181
6284
|
this.onProgress("__progress__:5:Downloading Docker Desktop...");
|
|
6182
|
-
const dlResult = await
|
|
6285
|
+
const dlResult = await runSilent("curl", [
|
|
6183
6286
|
"-fSL",
|
|
6184
|
-
"--progress-bar",
|
|
6185
6287
|
"-o",
|
|
6186
6288
|
dmgPath,
|
|
6187
6289
|
dmgUrl
|
|
@@ -6199,17 +6301,14 @@ var DependencyInstaller = class {
|
|
|
6199
6301
|
} catch {
|
|
6200
6302
|
throw new Error("Failed to mount Docker DMG. The download may be corrupted \u2014 try again.");
|
|
6201
6303
|
}
|
|
6304
|
+
this.preAcceptDockerLicense();
|
|
6202
6305
|
this.onProgress("__progress__:55:Running Docker installer...");
|
|
6203
6306
|
const user = process.env.USER || execSync("whoami", { timeout: 5e3 }).toString().trim();
|
|
6204
6307
|
try {
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
);
|
|
6210
|
-
if (installResult.exitCode !== 0 && !existsSync4("/Applications/Docker.app")) {
|
|
6211
|
-
throw new Error("Installer exited with errors");
|
|
6212
|
-
}
|
|
6308
|
+
execSync(`/Volumes/Docker/Docker.app/Contents/MacOS/install --accept-license --user=${user}`, {
|
|
6309
|
+
timeout: 12e4,
|
|
6310
|
+
stdio: "ignore"
|
|
6311
|
+
});
|
|
6213
6312
|
} catch {
|
|
6214
6313
|
if (!existsSync4("/Applications/Docker.app")) {
|
|
6215
6314
|
this.onProgress("__progress__:60:Trying alternative install method...");
|
|
@@ -6228,14 +6327,10 @@ var DependencyInstaller = class {
|
|
|
6228
6327
|
await unlink(dmgPath);
|
|
6229
6328
|
} catch {
|
|
6230
6329
|
}
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
this.onProgress("__progress__:70:Starting Docker Desktop...");
|
|
6236
|
-
this.startDockerDaemon();
|
|
6237
|
-
await this.waitForDocker();
|
|
6238
|
-
}
|
|
6330
|
+
this.onProgress("__progress__:70:Starting Docker engine...");
|
|
6331
|
+
this.startDockerDaemon();
|
|
6332
|
+
this.hideDockerWindow();
|
|
6333
|
+
await this.waitForDocker();
|
|
6239
6334
|
}
|
|
6240
6335
|
/**
|
|
6241
6336
|
* Install Docker Engine on Linux using Docker's official convenience script.
|
|
@@ -6423,6 +6518,7 @@ var DependencyInstaller = class {
|
|
|
6423
6518
|
const msgIdx = Math.floor(elapsed / 1e4) % msgs.length;
|
|
6424
6519
|
this.onProgress(`__progress__:${pct}:${msgs[msgIdx]}`);
|
|
6425
6520
|
}
|
|
6521
|
+
if (os === "darwin") this.hideDockerWindow();
|
|
6426
6522
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
6427
6523
|
}
|
|
6428
6524
|
throw new Error(
|
|
@@ -6537,7 +6633,7 @@ var DependencyInstaller = class {
|
|
|
6537
6633
|
|
|
6538
6634
|
// src/setup/service.ts
|
|
6539
6635
|
import { execFileSync as execFileSync3, execSync as execSync2 } from "child_process";
|
|
6540
|
-
import { existsSync as existsSync5, readFileSync as
|
|
6636
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
|
|
6541
6637
|
import { join as join7 } from "path";
|
|
6542
6638
|
import { homedir as homedir6, platform as platform3 } from "os";
|
|
6543
6639
|
var PLIST_LABEL = "com.agenticmail.server";
|
|
@@ -6600,7 +6696,7 @@ var ServiceManager = class {
|
|
|
6600
6696
|
const dataDir = join7(homedir6(), ".agenticmail");
|
|
6601
6697
|
const entryCache = join7(dataDir, "api-entry.path");
|
|
6602
6698
|
if (existsSync5(entryCache)) {
|
|
6603
|
-
const cached =
|
|
6699
|
+
const cached = readFileSync3(entryCache, "utf-8").trim();
|
|
6604
6700
|
if (existsSync5(cached)) return cached;
|
|
6605
6701
|
}
|
|
6606
6702
|
throw new Error("Could not find @agenticmail/api entry point. Run `agenticmail start` first to populate the cache.");
|
|
@@ -6611,7 +6707,7 @@ var ServiceManager = class {
|
|
|
6611
6707
|
cacheApiEntryPath(entryPath) {
|
|
6612
6708
|
const dataDir = join7(homedir6(), ".agenticmail");
|
|
6613
6709
|
if (!existsSync5(dataDir)) mkdirSync3(dataDir, { recursive: true });
|
|
6614
|
-
|
|
6710
|
+
writeFileSync4(join7(dataDir, "api-entry.path"), entryPath);
|
|
6615
6711
|
}
|
|
6616
6712
|
/**
|
|
6617
6713
|
* Get the current package version.
|
|
@@ -6629,7 +6725,7 @@ var ServiceManager = class {
|
|
|
6629
6725
|
}
|
|
6630
6726
|
for (const p of pkgPaths) {
|
|
6631
6727
|
if (existsSync5(p)) {
|
|
6632
|
-
const pkg = JSON.parse(
|
|
6728
|
+
const pkg = JSON.parse(readFileSync3(p, "utf-8"));
|
|
6633
6729
|
if (pkg.version) return pkg.version;
|
|
6634
6730
|
}
|
|
6635
6731
|
}
|
|
@@ -6695,7 +6791,7 @@ var ServiceManager = class {
|
|
|
6695
6791
|
`log "Starting API server: ${nodePath} ${apiEntry}"`,
|
|
6696
6792
|
`exec "${nodePath}" "${apiEntry}"`
|
|
6697
6793
|
].join("\n") + "\n";
|
|
6698
|
-
|
|
6794
|
+
writeFileSync4(scriptPath, script, { mode: 493 });
|
|
6699
6795
|
return scriptPath;
|
|
6700
6796
|
}
|
|
6701
6797
|
/**
|
|
@@ -6708,7 +6804,7 @@ var ServiceManager = class {
|
|
|
6708
6804
|
* - Service version tracking in env vars
|
|
6709
6805
|
*/
|
|
6710
6806
|
generatePlist(nodePath, apiEntry, configPath) {
|
|
6711
|
-
const config = JSON.parse(
|
|
6807
|
+
const config = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
6712
6808
|
const logDir = join7(homedir6(), ".agenticmail", "logs");
|
|
6713
6809
|
if (!existsSync5(logDir)) mkdirSync3(logDir, { recursive: true });
|
|
6714
6810
|
const version = this.getVersion();
|
|
@@ -6806,7 +6902,7 @@ var ServiceManager = class {
|
|
|
6806
6902
|
* - Proper dependency ordering
|
|
6807
6903
|
*/
|
|
6808
6904
|
generateSystemdUnit(nodePath, apiEntry, configPath) {
|
|
6809
|
-
const config = JSON.parse(
|
|
6905
|
+
const config = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
6810
6906
|
const dataDir = config.dataDir || join7(homedir6(), ".agenticmail");
|
|
6811
6907
|
const version = this.getVersion();
|
|
6812
6908
|
const startScript = this.generateStartScript(nodePath, apiEntry);
|
|
@@ -6869,7 +6965,7 @@ WantedBy=default.target
|
|
|
6869
6965
|
}
|
|
6870
6966
|
}
|
|
6871
6967
|
const plist = this.generatePlist(nodePath, apiEntry, configPath);
|
|
6872
|
-
|
|
6968
|
+
writeFileSync4(servicePath, plist);
|
|
6873
6969
|
try {
|
|
6874
6970
|
execFileSync3("launchctl", ["load", servicePath], { timeout: 1e4, stdio: "ignore" });
|
|
6875
6971
|
} catch (err) {
|
|
@@ -6880,7 +6976,7 @@ WantedBy=default.target
|
|
|
6880
6976
|
const dir = join7(homedir6(), ".config", "systemd", "user");
|
|
6881
6977
|
if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
|
|
6882
6978
|
const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
|
|
6883
|
-
|
|
6979
|
+
writeFileSync4(servicePath, unit);
|
|
6884
6980
|
try {
|
|
6885
6981
|
execFileSync3("systemctl", ["--user", "daemon-reload"], { timeout: 1e4, stdio: "ignore" });
|
|
6886
6982
|
execFileSync3("systemctl", ["--user", "enable", SYSTEMD_UNIT], { timeout: 1e4, stdio: "ignore" });
|
|
@@ -7031,7 +7127,7 @@ var SetupManager = class {
|
|
|
7031
7127
|
const envPath = join8(dataDir, ".env");
|
|
7032
7128
|
if (existsSync6(configPath)) {
|
|
7033
7129
|
try {
|
|
7034
|
-
const existing = JSON.parse(
|
|
7130
|
+
const existing = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
7035
7131
|
this.generateDockerFiles(existing);
|
|
7036
7132
|
return { configPath, envPath, config: existing, isNew: false };
|
|
7037
7133
|
} catch {
|
|
@@ -7054,7 +7150,7 @@ var SetupManager = class {
|
|
|
7054
7150
|
api: { port: 3100, host: "127.0.0.1" },
|
|
7055
7151
|
dataDir
|
|
7056
7152
|
};
|
|
7057
|
-
|
|
7153
|
+
writeFileSync5(configPath, JSON.stringify(config, null, 2));
|
|
7058
7154
|
chmodSync(configPath, 384);
|
|
7059
7155
|
const envContent = `# Auto-generated by agenticmail setup
|
|
7060
7156
|
STALWART_ADMIN_USER=admin
|
|
@@ -7070,7 +7166,7 @@ SMTP_PORT=587
|
|
|
7070
7166
|
IMAP_HOST=localhost
|
|
7071
7167
|
IMAP_PORT=143
|
|
7072
7168
|
`;
|
|
7073
|
-
|
|
7169
|
+
writeFileSync5(envPath, envContent);
|
|
7074
7170
|
chmodSync(envPath, 384);
|
|
7075
7171
|
this.generateDockerFiles(config);
|
|
7076
7172
|
return { configPath, envPath, config, isNew: true };
|
|
@@ -7086,7 +7182,7 @@ IMAP_PORT=143
|
|
|
7086
7182
|
}
|
|
7087
7183
|
const password = config.stalwart?.adminPassword || "changeme";
|
|
7088
7184
|
const composePath = join8(dataDir, "docker-compose.yml");
|
|
7089
|
-
|
|
7185
|
+
writeFileSync5(composePath, `services:
|
|
7090
7186
|
stalwart:
|
|
7091
7187
|
image: stalwartlabs/stalwart:latest
|
|
7092
7188
|
container_name: agenticmail-stalwart
|
|
@@ -7109,7 +7205,7 @@ volumes:
|
|
|
7109
7205
|
stalwart-data:
|
|
7110
7206
|
`);
|
|
7111
7207
|
const tomlPath = join8(dataDir, "stalwart.toml");
|
|
7112
|
-
|
|
7208
|
+
writeFileSync5(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
|
|
7113
7209
|
|
|
7114
7210
|
[server]
|
|
7115
7211
|
hostname = "localhost"
|