@agenticmail/core 0.9.3 → 0.9.5
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 +277 -92
- package/dist/index.d.cts +249 -1
- package/dist/index.d.ts +249 -1
- package/dist/index.js +266 -91
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -78,7 +78,7 @@ var MailSender = class {
|
|
|
78
78
|
const code = err?.responseCode ?? err?.code;
|
|
79
79
|
const isTransient = typeof code === "number" && code >= 400 && code < 500 || code === "ECONNRESET" || code === "ETIMEDOUT" || code === "ESOCKET";
|
|
80
80
|
if (!isTransient || attempt === MAX_RETRIES) throw err;
|
|
81
|
-
await new Promise((
|
|
81
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1e3 * (attempt + 1)));
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
throw lastError;
|
|
@@ -205,7 +205,13 @@ var MailReceiver = class {
|
|
|
205
205
|
async fetchMessage(uid, mailbox = "INBOX") {
|
|
206
206
|
const lock = await this.client.getMailboxLock(mailbox);
|
|
207
207
|
try {
|
|
208
|
-
const
|
|
208
|
+
const result = await this.client.download(String(uid), void 0, { uid: true });
|
|
209
|
+
const content = result?.content;
|
|
210
|
+
if (!content) {
|
|
211
|
+
const err = new Error(`Message UID ${uid} not found in mailbox "${mailbox}"`);
|
|
212
|
+
err.code = "MESSAGE_NOT_FOUND";
|
|
213
|
+
throw err;
|
|
214
|
+
}
|
|
209
215
|
const chunks = [];
|
|
210
216
|
for await (const chunk of content) {
|
|
211
217
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -1004,20 +1010,20 @@ var StalwartAdmin = class {
|
|
|
1004
1010
|
}
|
|
1005
1011
|
try {
|
|
1006
1012
|
const net = await import("net");
|
|
1007
|
-
return await new Promise((
|
|
1013
|
+
return await new Promise((resolve2) => {
|
|
1008
1014
|
const smtpPort = parseInt(process.env.SMTP_PORT || "25", 10);
|
|
1009
1015
|
const smtpHost = process.env.SMTP_HOST || "localhost";
|
|
1010
1016
|
const socket = net.createConnection({ host: smtpHost, port: smtpPort, timeout: 3e3 }, () => {
|
|
1011
1017
|
socket.destroy();
|
|
1012
|
-
|
|
1018
|
+
resolve2(true);
|
|
1013
1019
|
});
|
|
1014
1020
|
socket.on("error", () => {
|
|
1015
1021
|
socket.destroy();
|
|
1016
|
-
|
|
1022
|
+
resolve2(false);
|
|
1017
1023
|
});
|
|
1018
1024
|
socket.on("timeout", () => {
|
|
1019
1025
|
socket.destroy();
|
|
1020
|
-
|
|
1026
|
+
resolve2(false);
|
|
1021
1027
|
});
|
|
1022
1028
|
});
|
|
1023
1029
|
} catch {
|
|
@@ -1089,8 +1095,8 @@ var StalwartAdmin = class {
|
|
|
1089
1095
|
}
|
|
1090
1096
|
const { readFileSync: readFileSync7, writeFileSync: writeFileSync8 } = await import("fs");
|
|
1091
1097
|
const { homedir: homedir11 } = await import("os");
|
|
1092
|
-
const { join:
|
|
1093
|
-
const configPath =
|
|
1098
|
+
const { join: join13 } = await import("path");
|
|
1099
|
+
const configPath = join13(homedir11(), ".agenticmail", "stalwart.toml");
|
|
1094
1100
|
try {
|
|
1095
1101
|
let config = readFileSync7(configPath, "utf-8");
|
|
1096
1102
|
config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
|
|
@@ -1104,14 +1110,14 @@ var StalwartAdmin = class {
|
|
|
1104
1110
|
/** Path to the host-side stalwart.toml (mounted read-only into container) */
|
|
1105
1111
|
get configPath() {
|
|
1106
1112
|
const { homedir: homedir11 } = __require("os");
|
|
1107
|
-
const { join:
|
|
1108
|
-
return
|
|
1113
|
+
const { join: join13 } = __require("path");
|
|
1114
|
+
return join13(homedir11(), ".agenticmail", "stalwart.toml");
|
|
1109
1115
|
}
|
|
1110
1116
|
/** Path to host-side DKIM key directory */
|
|
1111
1117
|
get dkimDir() {
|
|
1112
1118
|
const { homedir: homedir11 } = __require("os");
|
|
1113
|
-
const { join:
|
|
1114
|
-
return
|
|
1119
|
+
const { join: join13 } = __require("path");
|
|
1120
|
+
return join13(homedir11(), ".agenticmail");
|
|
1115
1121
|
}
|
|
1116
1122
|
/**
|
|
1117
1123
|
* Create/reuse a DKIM signing key for a domain.
|
|
@@ -1214,9 +1220,9 @@ var StalwartAdmin = class {
|
|
|
1214
1220
|
async configureOutboundRelay(config) {
|
|
1215
1221
|
const { readFileSync: readFileSync7, writeFileSync: writeFileSync8 } = await import("fs");
|
|
1216
1222
|
const { homedir: homedir11 } = await import("os");
|
|
1217
|
-
const { join:
|
|
1223
|
+
const { join: join13 } = await import("path");
|
|
1218
1224
|
const routeName = config.routeName ?? "gmail";
|
|
1219
|
-
const tomlPath =
|
|
1225
|
+
const tomlPath = join13(homedir11(), ".agenticmail", "stalwart.toml");
|
|
1220
1226
|
let toml = readFileSync7(tomlPath, "utf-8");
|
|
1221
1227
|
toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
|
|
1222
1228
|
toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
|
|
@@ -2321,7 +2327,8 @@ var OUTBOUND_TEXT_RULES = [
|
|
|
2321
2327
|
var HIGH_RISK_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".p12", ".pfx", ".env", ".credentials", ".keystore", ".jks", ".p8"]);
|
|
2322
2328
|
var MEDIUM_RISK_EXTENSIONS = /* @__PURE__ */ new Set([".db", ".sqlite", ".sqlite3", ".sql", ".csv", ".tsv", ".json", ".yml", ".yaml", ".conf", ".config", ".ini"]);
|
|
2323
2329
|
function stripHtmlTags(html) {
|
|
2324
|
-
|
|
2330
|
+
const bounded = html.length > 1048576 ? html.slice(0, 1048576) : html;
|
|
2331
|
+
return bounded.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/�?39;/g, "'").replace(/ /g, " ").replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));
|
|
2325
2332
|
}
|
|
2326
2333
|
var TEXT_SCANNABLE_TYPES = /* @__PURE__ */ new Set([
|
|
2327
2334
|
"text/plain",
|
|
@@ -3853,7 +3860,7 @@ var CloudflareClient = class {
|
|
|
3853
3860
|
// --- Workers methods ---
|
|
3854
3861
|
/** Deploy an Email Worker script (ES module format) */
|
|
3855
3862
|
async deployEmailWorker(scriptName, scriptContent, envVars = {}) {
|
|
3856
|
-
const url = `${CF_API_BASE}/accounts/${this.accountId}/workers/scripts/${scriptName}`;
|
|
3863
|
+
const url = `${CF_API_BASE}/accounts/${encodeURIComponent(this.accountId)}/workers/scripts/${encodeURIComponent(scriptName)}`;
|
|
3857
3864
|
const bindings = Object.entries(envVars).map(([name, text2]) => ({
|
|
3858
3865
|
type: "plain_text",
|
|
3859
3866
|
name,
|
|
@@ -4271,7 +4278,7 @@ var TunnelManager = class {
|
|
|
4271
4278
|
detached: false,
|
|
4272
4279
|
env: { ...process.env, TUNNEL_TOKEN: tunnelToken }
|
|
4273
4280
|
});
|
|
4274
|
-
await new Promise((
|
|
4281
|
+
await new Promise((resolve2, reject) => {
|
|
4275
4282
|
let resolved = false;
|
|
4276
4283
|
const timeout = setTimeout(() => {
|
|
4277
4284
|
if (!resolved) {
|
|
@@ -4285,7 +4292,7 @@ var TunnelManager = class {
|
|
|
4285
4292
|
resolved = true;
|
|
4286
4293
|
clearTimeout(timeout);
|
|
4287
4294
|
this.running = true;
|
|
4288
|
-
|
|
4295
|
+
resolve2();
|
|
4289
4296
|
}
|
|
4290
4297
|
};
|
|
4291
4298
|
this.process.stderr?.on("data", onData);
|
|
@@ -4324,8 +4331,8 @@ var TunnelManager = class {
|
|
|
4324
4331
|
this.process = null;
|
|
4325
4332
|
p.kill("SIGTERM");
|
|
4326
4333
|
await Promise.race([
|
|
4327
|
-
new Promise((
|
|
4328
|
-
new Promise((
|
|
4334
|
+
new Promise((resolve2) => p.on("exit", () => resolve2())),
|
|
4335
|
+
new Promise((resolve2) => setTimeout(resolve2, 5e3))
|
|
4329
4336
|
]);
|
|
4330
4337
|
this.running = false;
|
|
4331
4338
|
}
|
|
@@ -4380,7 +4387,10 @@ function parseGoogleVoiceSms(emailBody, emailFrom) {
|
|
|
4380
4387
|
if (!emailBody || typeof emailBody !== "string") return null;
|
|
4381
4388
|
if (!emailFrom || typeof emailFrom !== "string") return null;
|
|
4382
4389
|
const fromLower = emailFrom.toLowerCase();
|
|
4383
|
-
const
|
|
4390
|
+
const atIdx = fromLower.lastIndexOf("@");
|
|
4391
|
+
const domain = atIdx >= 0 ? fromLower.slice(atIdx + 1).replace(/[>"'\s].*$/, "") : "";
|
|
4392
|
+
const isGoogleDomain = domain === "google.com" || domain.endsWith(".google.com");
|
|
4393
|
+
const isGoogleVoice = isGoogleDomain && (fromLower.startsWith("voice-noreply@") || domain === "txt.voice.google.com" || domain === "voice.google.com" || domain.endsWith(".voice.google.com") || fromLower.includes("voice"));
|
|
4384
4394
|
if (!isGoogleVoice) return null;
|
|
4385
4395
|
let text = emailBody.replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<\/div>/gi, "\n").replace(/<[^>]+>/g, "").replace(/ /gi, " ").replace(/&/gi, "&").replace(/</gi, "<").replace(/>/gi, ">").replace(/"/gi, '"').replace(/'/gi, "'").trim();
|
|
4386
4396
|
let from = "";
|
|
@@ -5411,6 +5421,15 @@ var GatewayManager = class {
|
|
|
5411
5421
|
bcc: mail.bcc ? Array.isArray(mail.bcc) ? mail.bcc.join(", ") : mail.bcc : void 0,
|
|
5412
5422
|
subject: mail.subject,
|
|
5413
5423
|
text: mail.text || void 0,
|
|
5424
|
+
// The `html` field is the literal HTML body of the outbound
|
|
5425
|
+
// mail — by design it is whatever the sender chose to compose.
|
|
5426
|
+
// CodeQL `js/xss` flags this because the value flows from user
|
|
5427
|
+
// input, but nodemailer is the SMTP serializer, not an HTML
|
|
5428
|
+
// renderer; XSS would only occur if the recipient's MUA
|
|
5429
|
+
// executed the body, which is outside our trust boundary.
|
|
5430
|
+
// The outbound-guard (packages/core/src/mail/outbound-guard.ts)
|
|
5431
|
+
// already scores HTML bodies for suspicious patterns at the
|
|
5432
|
+
// pre-send step. lgtm[js/xss]
|
|
5414
5433
|
html: mail.html || void 0,
|
|
5415
5434
|
replyTo: mail.replyTo || from,
|
|
5416
5435
|
inReplyTo: mail.inReplyTo || void 0,
|
|
@@ -5772,11 +5791,11 @@ var RelayBridge = class {
|
|
|
5772
5791
|
this.options = options;
|
|
5773
5792
|
}
|
|
5774
5793
|
async start() {
|
|
5775
|
-
return new Promise((
|
|
5794
|
+
return new Promise((resolve2, reject) => {
|
|
5776
5795
|
this.server = createServer((req, res) => this.handleRequest(req, res));
|
|
5777
5796
|
this.server.listen(this.options.port, "127.0.0.1", () => {
|
|
5778
5797
|
console.log(`[RelayBridge] Listening on 127.0.0.1:${this.options.port}`);
|
|
5779
|
-
|
|
5798
|
+
resolve2();
|
|
5780
5799
|
});
|
|
5781
5800
|
this.server.on("error", reject);
|
|
5782
5801
|
});
|
|
@@ -5978,16 +5997,161 @@ try {
|
|
|
5978
5997
|
} catch {
|
|
5979
5998
|
}
|
|
5980
5999
|
|
|
6000
|
+
// src/util/safe-path.ts
|
|
6001
|
+
import { isAbsolute, join as join6, resolve, sep } from "path";
|
|
6002
|
+
var PathTraversalError = class extends Error {
|
|
6003
|
+
constructor(baseDir, parts) {
|
|
6004
|
+
super(
|
|
6005
|
+
`path traversal attempt: ${JSON.stringify(parts)} resolves outside ${baseDir}`
|
|
6006
|
+
);
|
|
6007
|
+
this.baseDir = baseDir;
|
|
6008
|
+
this.parts = parts;
|
|
6009
|
+
this.name = "PathTraversalError";
|
|
6010
|
+
}
|
|
6011
|
+
};
|
|
6012
|
+
function safeJoin(baseDir, ...partsAndOpts) {
|
|
6013
|
+
let opts = {};
|
|
6014
|
+
const parts = [];
|
|
6015
|
+
for (const p of partsAndOpts) {
|
|
6016
|
+
if (typeof p === "string") {
|
|
6017
|
+
parts.push(p);
|
|
6018
|
+
} else if (p && typeof p === "object") {
|
|
6019
|
+
opts = p;
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
6022
|
+
if (!opts.allowAbsolute) {
|
|
6023
|
+
for (const part of parts) {
|
|
6024
|
+
if (isAbsolute(part)) {
|
|
6025
|
+
throw new PathTraversalError(baseDir, parts);
|
|
6026
|
+
}
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
const resolvedBase = resolve(baseDir);
|
|
6030
|
+
const resolved = resolve(resolvedBase, ...parts);
|
|
6031
|
+
if (resolved !== resolvedBase && !resolved.startsWith(resolvedBase + sep)) {
|
|
6032
|
+
throw new PathTraversalError(baseDir, parts);
|
|
6033
|
+
}
|
|
6034
|
+
return resolved;
|
|
6035
|
+
}
|
|
6036
|
+
function tryJoin(baseDir, ...parts) {
|
|
6037
|
+
try {
|
|
6038
|
+
return safeJoin(baseDir, ...parts);
|
|
6039
|
+
} catch (err) {
|
|
6040
|
+
if (err instanceof PathTraversalError) return null;
|
|
6041
|
+
throw err;
|
|
6042
|
+
}
|
|
6043
|
+
}
|
|
6044
|
+
function assertWithinBase(baseDir, candidate) {
|
|
6045
|
+
const resolvedBase = resolve(baseDir);
|
|
6046
|
+
const resolvedCandidate = resolve(candidate);
|
|
6047
|
+
if (resolvedCandidate !== resolvedBase && !resolvedCandidate.startsWith(resolvedBase + sep)) {
|
|
6048
|
+
throw new PathTraversalError(baseDir, [candidate]);
|
|
6049
|
+
}
|
|
6050
|
+
return resolvedCandidate;
|
|
6051
|
+
}
|
|
6052
|
+
|
|
6053
|
+
// src/util/redact.ts
|
|
6054
|
+
var REDACTED = "***";
|
|
6055
|
+
function redactSecret(value) {
|
|
6056
|
+
if (typeof value !== "string") return REDACTED;
|
|
6057
|
+
if (value.length === 0) return REDACTED;
|
|
6058
|
+
for (const prefix of ["mk_", "ak_", "sk-", "pk_", "tok_"]) {
|
|
6059
|
+
if (value.startsWith(prefix)) return `${prefix}${REDACTED}`;
|
|
6060
|
+
}
|
|
6061
|
+
return REDACTED;
|
|
6062
|
+
}
|
|
6063
|
+
var SENSITIVE_KEY_PATTERNS = [
|
|
6064
|
+
/key$/i,
|
|
6065
|
+
/secret/i,
|
|
6066
|
+
/password/i,
|
|
6067
|
+
/passwd/i,
|
|
6068
|
+
/token/i,
|
|
6069
|
+
/authorization/i,
|
|
6070
|
+
/bearer/i,
|
|
6071
|
+
/\bapikey\b/i,
|
|
6072
|
+
/\bapi_key\b/i,
|
|
6073
|
+
/\bmasterkey\b/i,
|
|
6074
|
+
/\bmaster_key\b/i
|
|
6075
|
+
];
|
|
6076
|
+
function looksSensitive(key) {
|
|
6077
|
+
return SENSITIVE_KEY_PATTERNS.some((p) => p.test(key));
|
|
6078
|
+
}
|
|
6079
|
+
function redactObject(input, _depth = 0) {
|
|
6080
|
+
if (_depth > 12) return input;
|
|
6081
|
+
if (input === null || input === void 0) return input;
|
|
6082
|
+
if (typeof input !== "object") return input;
|
|
6083
|
+
if (Array.isArray(input)) {
|
|
6084
|
+
return input.map((v) => redactObject(v, _depth + 1));
|
|
6085
|
+
}
|
|
6086
|
+
const proto = Object.getPrototypeOf(input);
|
|
6087
|
+
if (proto !== Object.prototype && proto !== null) return input;
|
|
6088
|
+
const out = {};
|
|
6089
|
+
for (const [k, v] of Object.entries(input)) {
|
|
6090
|
+
if (looksSensitive(k)) {
|
|
6091
|
+
out[k] = typeof v === "string" ? redactSecret(v) : REDACTED;
|
|
6092
|
+
} else {
|
|
6093
|
+
out[k] = redactObject(v, _depth + 1);
|
|
6094
|
+
}
|
|
6095
|
+
}
|
|
6096
|
+
return out;
|
|
6097
|
+
}
|
|
6098
|
+
|
|
6099
|
+
// src/util/safe-url.ts
|
|
6100
|
+
var UnsafeApiUrlError = class extends Error {
|
|
6101
|
+
constructor(raw, reason) {
|
|
6102
|
+
super(`unsafe AgenticMail API URL ${JSON.stringify(raw)}: ${reason}`);
|
|
6103
|
+
this.raw = raw;
|
|
6104
|
+
this.reason = reason;
|
|
6105
|
+
this.name = "UnsafeApiUrlError";
|
|
6106
|
+
}
|
|
6107
|
+
};
|
|
6108
|
+
var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
|
|
6109
|
+
"169.254.169.254",
|
|
6110
|
+
// AWS / Azure / GCP IPv4 metadata
|
|
6111
|
+
"fd00:ec2::254",
|
|
6112
|
+
// AWS IPv6 metadata
|
|
6113
|
+
"metadata.google.internal",
|
|
6114
|
+
// GCP DNS
|
|
6115
|
+
"metadata.azure.internal"
|
|
6116
|
+
// Azure DNS
|
|
6117
|
+
]);
|
|
6118
|
+
function validateApiUrl(raw) {
|
|
6119
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
6120
|
+
throw new UnsafeApiUrlError(String(raw), "must be a non-empty string");
|
|
6121
|
+
}
|
|
6122
|
+
let parsed;
|
|
6123
|
+
try {
|
|
6124
|
+
parsed = new URL(raw);
|
|
6125
|
+
} catch (err) {
|
|
6126
|
+
throw new UnsafeApiUrlError(raw, `unparseable: ${err.message}`);
|
|
6127
|
+
}
|
|
6128
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
6129
|
+
throw new UnsafeApiUrlError(raw, `unsupported protocol: ${parsed.protocol}`);
|
|
6130
|
+
}
|
|
6131
|
+
const host = parsed.hostname.toLowerCase().replace(/\.$/, "");
|
|
6132
|
+
if (BLOCKED_HOSTS.has(host)) {
|
|
6133
|
+
throw new UnsafeApiUrlError(raw, `blocked metadata host: ${host}`);
|
|
6134
|
+
}
|
|
6135
|
+
if (parsed.username || parsed.password) {
|
|
6136
|
+
throw new UnsafeApiUrlError(raw, "embedded credentials are not supported");
|
|
6137
|
+
}
|
|
6138
|
+
return parsed.origin;
|
|
6139
|
+
}
|
|
6140
|
+
function buildApiUrl(baseOrigin, pathAndQuery) {
|
|
6141
|
+
const path = pathAndQuery.startsWith("/") ? pathAndQuery : `/${pathAndQuery}`;
|
|
6142
|
+
return new URL(path, baseOrigin + "/").toString();
|
|
6143
|
+
}
|
|
6144
|
+
|
|
5981
6145
|
// src/setup/index.ts
|
|
5982
6146
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
5983
6147
|
import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, chmodSync as chmodSync2 } from "fs";
|
|
5984
|
-
import { join as
|
|
6148
|
+
import { join as join10 } from "path";
|
|
5985
6149
|
import { homedir as homedir8 } from "os";
|
|
5986
6150
|
|
|
5987
6151
|
// src/setup/deps.ts
|
|
5988
6152
|
import { execFileSync } from "child_process";
|
|
5989
6153
|
import { existsSync as existsSync4 } from "fs";
|
|
5990
|
-
import { join as
|
|
6154
|
+
import { join as join7 } from "path";
|
|
5991
6155
|
import { homedir as homedir5 } from "os";
|
|
5992
6156
|
var DependencyChecker = class {
|
|
5993
6157
|
async checkAll() {
|
|
@@ -6038,7 +6202,7 @@ var DependencyChecker = class {
|
|
|
6038
6202
|
}
|
|
6039
6203
|
}
|
|
6040
6204
|
async checkCloudflared() {
|
|
6041
|
-
const binPath =
|
|
6205
|
+
const binPath = join7(homedir5(), ".agenticmail", "bin", "cloudflared");
|
|
6042
6206
|
if (existsSync4(binPath)) {
|
|
6043
6207
|
let version;
|
|
6044
6208
|
try {
|
|
@@ -6063,12 +6227,12 @@ var DependencyChecker = class {
|
|
|
6063
6227
|
import { execFileSync as execFileSync2, execSync, spawn as spawnChild } from "child_process";
|
|
6064
6228
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, symlinkSync } from "fs";
|
|
6065
6229
|
import { writeFile, rename, chmod as chmod2, mkdir as mkdir2, unlink } from "fs/promises";
|
|
6066
|
-
import { join as
|
|
6230
|
+
import { join as join8 } from "path";
|
|
6067
6231
|
import { homedir as homedir6, platform as platform3, arch as arch2 } from "os";
|
|
6068
6232
|
function runShellWithRollingOutput(cmd, opts = {}) {
|
|
6069
6233
|
const maxLines = opts.maxLines ?? 20;
|
|
6070
6234
|
const timeout = opts.timeout ?? 3e5;
|
|
6071
|
-
return new Promise((
|
|
6235
|
+
return new Promise((resolve2, reject) => {
|
|
6072
6236
|
const child = spawnChild("sh", ["-c", cmd], {
|
|
6073
6237
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6074
6238
|
timeout
|
|
@@ -6110,7 +6274,7 @@ function runShellWithRollingOutput(cmd, opts = {}) {
|
|
|
6110
6274
|
}
|
|
6111
6275
|
process.stdout.write(`\x1B[${displayedCount}A`);
|
|
6112
6276
|
}
|
|
6113
|
-
|
|
6277
|
+
resolve2({ exitCode: code ?? 1, fullOutput });
|
|
6114
6278
|
});
|
|
6115
6279
|
child.on("error", (err) => {
|
|
6116
6280
|
if (displayedCount > 0) {
|
|
@@ -6126,7 +6290,7 @@ function runShellWithRollingOutput(cmd, opts = {}) {
|
|
|
6126
6290
|
}
|
|
6127
6291
|
function runSilent(command, args, opts = {}) {
|
|
6128
6292
|
const timeout = opts.timeout ?? 3e5;
|
|
6129
|
-
return new Promise((
|
|
6293
|
+
return new Promise((resolve2, reject) => {
|
|
6130
6294
|
const child = spawnChild(command, args, {
|
|
6131
6295
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6132
6296
|
timeout
|
|
@@ -6138,7 +6302,7 @@ function runSilent(command, args, opts = {}) {
|
|
|
6138
6302
|
child.stderr?.on("data", (d) => {
|
|
6139
6303
|
fullOutput += d.toString();
|
|
6140
6304
|
});
|
|
6141
|
-
child.on("close", (code) =>
|
|
6305
|
+
child.on("close", (code) => resolve2({ exitCode: code ?? 1, fullOutput }));
|
|
6142
6306
|
child.on("error", reject);
|
|
6143
6307
|
});
|
|
6144
6308
|
}
|
|
@@ -6240,8 +6404,8 @@ var DependencyInstaller = class {
|
|
|
6240
6404
|
try {
|
|
6241
6405
|
const composeBin = execFileSync2("which", ["docker-compose"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
6242
6406
|
if (!composeBin) return;
|
|
6243
|
-
const pluginDir =
|
|
6244
|
-
const pluginPath =
|
|
6407
|
+
const pluginDir = join8(homedir6(), ".docker", "cli-plugins");
|
|
6408
|
+
const pluginPath = join8(pluginDir, "docker-compose");
|
|
6245
6409
|
if (existsSync5(pluginPath)) return;
|
|
6246
6410
|
try {
|
|
6247
6411
|
mkdirSync4(pluginDir, { recursive: true });
|
|
@@ -6307,9 +6471,9 @@ var DependencyInstaller = class {
|
|
|
6307
6471
|
return;
|
|
6308
6472
|
}
|
|
6309
6473
|
this.onProgress("__progress__:5:Installing Docker Engine...");
|
|
6310
|
-
const tmpDir =
|
|
6474
|
+
const tmpDir = join8(homedir6(), ".agenticmail", "tmp");
|
|
6311
6475
|
await mkdir2(tmpDir, { recursive: true });
|
|
6312
|
-
const scriptPath =
|
|
6476
|
+
const scriptPath = join8(tmpDir, "install-docker.sh");
|
|
6313
6477
|
const dlResult = await runShellWithRollingOutput(
|
|
6314
6478
|
`curl -fsSL https://get.docker.com -o "${scriptPath}" && sudo sh "${scriptPath}"`,
|
|
6315
6479
|
{ timeout: 3e5 }
|
|
@@ -6377,7 +6541,7 @@ var DependencyInstaller = class {
|
|
|
6377
6541
|
}
|
|
6378
6542
|
try {
|
|
6379
6543
|
const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
|
|
6380
|
-
const dockerExe =
|
|
6544
|
+
const dockerExe = join8(programFiles, "Docker", "Docker", "Docker Desktop.exe");
|
|
6381
6545
|
if (existsSync5(dockerExe)) {
|
|
6382
6546
|
execSync(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
|
|
6383
6547
|
}
|
|
@@ -6428,7 +6592,7 @@ var DependencyInstaller = class {
|
|
|
6428
6592
|
this.onProgress("__progress__:70:Docker Desktop installed. Starting...");
|
|
6429
6593
|
try {
|
|
6430
6594
|
const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
|
|
6431
|
-
const dockerExe =
|
|
6595
|
+
const dockerExe = join8(programFiles, "Docker", "Docker", "Docker Desktop.exe");
|
|
6432
6596
|
if (existsSync5(dockerExe)) {
|
|
6433
6597
|
execSync(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
|
|
6434
6598
|
}
|
|
@@ -6525,9 +6689,9 @@ var DependencyInstaller = class {
|
|
|
6525
6689
|
*/
|
|
6526
6690
|
async installCloudflared() {
|
|
6527
6691
|
const os = platform3();
|
|
6528
|
-
const binDir =
|
|
6692
|
+
const binDir = join8(homedir6(), ".agenticmail", "bin");
|
|
6529
6693
|
const binName = os === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
6530
|
-
const binPath =
|
|
6694
|
+
const binPath = join8(binDir, binName);
|
|
6531
6695
|
if (existsSync5(binPath)) {
|
|
6532
6696
|
return binPath;
|
|
6533
6697
|
}
|
|
@@ -6557,7 +6721,7 @@ var DependencyInstaller = class {
|
|
|
6557
6721
|
}
|
|
6558
6722
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
6559
6723
|
if (os === "darwin") {
|
|
6560
|
-
const tgzPath =
|
|
6724
|
+
const tgzPath = join8(binDir, "cloudflared.tgz");
|
|
6561
6725
|
await writeFile(tgzPath, buffer);
|
|
6562
6726
|
try {
|
|
6563
6727
|
execFileSync2("tar", ["-xzf", tgzPath, "-C", binDir, "cloudflared"], { timeout: 15e3, stdio: "ignore" });
|
|
@@ -6593,7 +6757,7 @@ var DependencyInstaller = class {
|
|
|
6593
6757
|
// src/setup/service.ts
|
|
6594
6758
|
import { execFileSync as execFileSync3, execSync as execSync2 } from "child_process";
|
|
6595
6759
|
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync5, chmodSync } from "fs";
|
|
6596
|
-
import { join as
|
|
6760
|
+
import { join as join9 } from "path";
|
|
6597
6761
|
import { homedir as homedir7, platform as platform4 } from "os";
|
|
6598
6762
|
import { createRequire as createRequire2 } from "module";
|
|
6599
6763
|
var PLIST_LABEL = "com.agenticmail.server";
|
|
@@ -6605,9 +6769,9 @@ var ServiceManager = class {
|
|
|
6605
6769
|
*/
|
|
6606
6770
|
getServicePath() {
|
|
6607
6771
|
if (this.os === "darwin") {
|
|
6608
|
-
return
|
|
6772
|
+
return join9(homedir7(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
6609
6773
|
} else {
|
|
6610
|
-
return
|
|
6774
|
+
return join9(homedir7(), ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
6611
6775
|
}
|
|
6612
6776
|
}
|
|
6613
6777
|
/**
|
|
@@ -6645,33 +6809,33 @@ var ServiceManager = class {
|
|
|
6645
6809
|
} catch {
|
|
6646
6810
|
}
|
|
6647
6811
|
const parentPackages = [
|
|
6648
|
-
|
|
6812
|
+
join9("@agenticmail", "cli"),
|
|
6649
6813
|
// current scoped package
|
|
6650
6814
|
"agenticmail"
|
|
6651
6815
|
// legacy unscoped package
|
|
6652
6816
|
];
|
|
6653
6817
|
const baseDirs = [
|
|
6654
6818
|
// user-local install
|
|
6655
|
-
|
|
6819
|
+
join9(homedir7(), "node_modules")
|
|
6656
6820
|
];
|
|
6657
6821
|
try {
|
|
6658
6822
|
const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
6659
|
-
baseDirs.push(
|
|
6660
|
-
baseDirs.push(
|
|
6823
|
+
baseDirs.push(join9(prefix, "lib", "node_modules"));
|
|
6824
|
+
baseDirs.push(join9(prefix, "node_modules"));
|
|
6661
6825
|
} catch {
|
|
6662
6826
|
}
|
|
6663
6827
|
baseDirs.push("/opt/homebrew/lib/node_modules");
|
|
6664
6828
|
baseDirs.push("/usr/local/lib/node_modules");
|
|
6665
6829
|
for (const base of baseDirs) {
|
|
6666
|
-
const sibling =
|
|
6830
|
+
const sibling = join9(base, "@agenticmail", "api", "dist", "index.js");
|
|
6667
6831
|
if (existsSync6(sibling)) return sibling;
|
|
6668
6832
|
for (const parent of parentPackages) {
|
|
6669
|
-
const nested =
|
|
6833
|
+
const nested = join9(base, parent, "node_modules", "@agenticmail", "api", "dist", "index.js");
|
|
6670
6834
|
if (existsSync6(nested)) return nested;
|
|
6671
6835
|
}
|
|
6672
6836
|
}
|
|
6673
|
-
const dataDir =
|
|
6674
|
-
const entryCache =
|
|
6837
|
+
const dataDir = join9(homedir7(), ".agenticmail");
|
|
6838
|
+
const entryCache = join9(dataDir, "api-entry.path");
|
|
6675
6839
|
if (existsSync6(entryCache)) {
|
|
6676
6840
|
const cached = readFileSync3(entryCache, "utf-8").trim();
|
|
6677
6841
|
if (cached && existsSync6(cached)) return cached;
|
|
@@ -6682,9 +6846,9 @@ var ServiceManager = class {
|
|
|
6682
6846
|
* Cache the API entry path so the service can find it later.
|
|
6683
6847
|
*/
|
|
6684
6848
|
cacheApiEntryPath(entryPath) {
|
|
6685
|
-
const dataDir =
|
|
6849
|
+
const dataDir = join9(homedir7(), ".agenticmail");
|
|
6686
6850
|
if (!existsSync6(dataDir)) mkdirSync5(dataDir, { recursive: true });
|
|
6687
|
-
writeFileSync4(
|
|
6851
|
+
writeFileSync4(join9(dataDir, "api-entry.path"), entryPath);
|
|
6688
6852
|
}
|
|
6689
6853
|
/**
|
|
6690
6854
|
* Get the current package version.
|
|
@@ -6705,7 +6869,7 @@ var ServiceManager = class {
|
|
|
6705
6869
|
}
|
|
6706
6870
|
try {
|
|
6707
6871
|
const apiEntry = this.getApiEntryPath();
|
|
6708
|
-
const apiPkg =
|
|
6872
|
+
const apiPkg = join9(apiEntry, "..", "..", "package.json");
|
|
6709
6873
|
if (existsSync6(apiPkg)) {
|
|
6710
6874
|
const pkg = JSON.parse(readFileSync3(apiPkg, "utf-8"));
|
|
6711
6875
|
if (pkg.version) return pkg.version;
|
|
@@ -6713,14 +6877,14 @@ var ServiceManager = class {
|
|
|
6713
6877
|
} catch {
|
|
6714
6878
|
}
|
|
6715
6879
|
const candidates = [
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6880
|
+
join9(homedir7(), "node_modules", "@agenticmail", "cli", "package.json"),
|
|
6881
|
+
join9(homedir7(), "node_modules", "agenticmail", "package.json"),
|
|
6882
|
+
join9(homedir7(), ".agenticmail", "package-version.json")
|
|
6719
6883
|
];
|
|
6720
6884
|
try {
|
|
6721
6885
|
const prefix = execSync2("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
6722
|
-
candidates.push(
|
|
6723
|
-
candidates.push(
|
|
6886
|
+
candidates.push(join9(prefix, "lib", "node_modules", "@agenticmail", "cli", "package.json"));
|
|
6887
|
+
candidates.push(join9(prefix, "lib", "node_modules", "agenticmail", "package.json"));
|
|
6724
6888
|
} catch {
|
|
6725
6889
|
}
|
|
6726
6890
|
for (const p of candidates) {
|
|
@@ -6739,8 +6903,8 @@ var ServiceManager = class {
|
|
|
6739
6903
|
* This ensures AgenticMail doesn't fail on boot when Docker is still loading.
|
|
6740
6904
|
*/
|
|
6741
6905
|
generateStartScript(nodePath, apiEntry) {
|
|
6742
|
-
const scriptPath =
|
|
6743
|
-
const scriptDir =
|
|
6906
|
+
const scriptPath = join9(homedir7(), ".agenticmail", "bin", "start-server.sh");
|
|
6907
|
+
const scriptDir = join9(homedir7(), ".agenticmail", "bin");
|
|
6744
6908
|
if (!existsSync6(scriptDir)) mkdirSync5(scriptDir, { recursive: true });
|
|
6745
6909
|
const script = [
|
|
6746
6910
|
"#!/bin/bash",
|
|
@@ -6806,7 +6970,7 @@ var ServiceManager = class {
|
|
|
6806
6970
|
*/
|
|
6807
6971
|
generatePlist(nodePath, apiEntry, configPath) {
|
|
6808
6972
|
const config = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
6809
|
-
const logDir =
|
|
6973
|
+
const logDir = join9(homedir7(), ".agenticmail", "logs");
|
|
6810
6974
|
if (!existsSync6(logDir)) mkdirSync5(logDir, { recursive: true });
|
|
6811
6975
|
const version = this.getVersion();
|
|
6812
6976
|
const startScript = this.generateStartScript(nodePath, apiEntry);
|
|
@@ -6830,7 +6994,7 @@ var ServiceManager = class {
|
|
|
6830
6994
|
<key>HOME</key>
|
|
6831
6995
|
<string>${homedir7()}</string>
|
|
6832
6996
|
<key>AGENTICMAIL_DATA_DIR</key>
|
|
6833
|
-
<string>${config.dataDir ||
|
|
6997
|
+
<string>${config.dataDir || join9(homedir7(), ".agenticmail")}</string>
|
|
6834
6998
|
<key>PATH</key>
|
|
6835
6999
|
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
6836
7000
|
<key>AGENTICMAIL_SERVICE_VERSION</key>
|
|
@@ -6884,7 +7048,7 @@ var ServiceManager = class {
|
|
|
6884
7048
|
*/
|
|
6885
7049
|
generateSystemdUnit(nodePath, apiEntry, configPath) {
|
|
6886
7050
|
const config = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
6887
|
-
const dataDir = config.dataDir ||
|
|
7051
|
+
const dataDir = config.dataDir || join9(homedir7(), ".agenticmail");
|
|
6888
7052
|
const version = this.getVersion();
|
|
6889
7053
|
const startScript = this.generateStartScript(nodePath, apiEntry);
|
|
6890
7054
|
return `[Unit]
|
|
@@ -6914,7 +7078,7 @@ WantedBy=default.target
|
|
|
6914
7078
|
* Install the auto-start service.
|
|
6915
7079
|
*/
|
|
6916
7080
|
install() {
|
|
6917
|
-
const configPath =
|
|
7081
|
+
const configPath = join9(homedir7(), ".agenticmail", "config.json");
|
|
6918
7082
|
if (!existsSync6(configPath)) {
|
|
6919
7083
|
return { installed: false, message: "Config not found. Run agenticmail setup first." };
|
|
6920
7084
|
}
|
|
@@ -6927,7 +7091,7 @@ WantedBy=default.target
|
|
|
6927
7091
|
}
|
|
6928
7092
|
const servicePath = this.getServicePath();
|
|
6929
7093
|
if (this.os === "darwin") {
|
|
6930
|
-
const dir =
|
|
7094
|
+
const dir = join9(homedir7(), "Library", "LaunchAgents");
|
|
6931
7095
|
if (!existsSync6(dir)) mkdirSync5(dir, { recursive: true });
|
|
6932
7096
|
if (existsSync6(servicePath)) {
|
|
6933
7097
|
try {
|
|
@@ -6945,7 +7109,7 @@ WantedBy=default.target
|
|
|
6945
7109
|
}
|
|
6946
7110
|
return { installed: true, message: `Service installed at ${servicePath}` };
|
|
6947
7111
|
} else if (this.os === "linux") {
|
|
6948
|
-
const dir =
|
|
7112
|
+
const dir = join9(homedir7(), ".config", "systemd", "user");
|
|
6949
7113
|
if (!existsSync6(dir)) mkdirSync5(dir, { recursive: true });
|
|
6950
7114
|
const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
|
|
6951
7115
|
writeFileSync4(servicePath, unit);
|
|
@@ -7071,7 +7235,7 @@ WantedBy=default.target
|
|
|
7071
7235
|
} catch {
|
|
7072
7236
|
return { reason: "Service file unreadable" };
|
|
7073
7237
|
}
|
|
7074
|
-
const startScript =
|
|
7238
|
+
const startScript = join9(homedir7(), ".agenticmail", "bin", "start-server.sh");
|
|
7075
7239
|
if (serviceContent.includes(startScript)) {
|
|
7076
7240
|
if (!existsSync6(startScript)) {
|
|
7077
7241
|
return { reason: "start-server.sh is missing" };
|
|
@@ -7104,7 +7268,7 @@ WantedBy=default.target
|
|
|
7104
7268
|
return { reason: `Service version drift (current CLI is v${currentVersion})` };
|
|
7105
7269
|
}
|
|
7106
7270
|
}
|
|
7107
|
-
const entryCache =
|
|
7271
|
+
const entryCache = join9(homedir7(), ".agenticmail", "api-entry.path");
|
|
7108
7272
|
if (existsSync6(entryCache)) {
|
|
7109
7273
|
try {
|
|
7110
7274
|
const cached = readFileSync3(entryCache, "utf-8").trim();
|
|
@@ -7159,12 +7323,12 @@ var SetupManager = class {
|
|
|
7159
7323
|
* falls back to monorepo location.
|
|
7160
7324
|
*/
|
|
7161
7325
|
getComposePath() {
|
|
7162
|
-
const standalonePath =
|
|
7326
|
+
const standalonePath = join10(homedir8(), ".agenticmail", "docker-compose.yml");
|
|
7163
7327
|
if (existsSync7(standalonePath)) return standalonePath;
|
|
7164
7328
|
const cwd = process.cwd();
|
|
7165
|
-
const candidates = [cwd,
|
|
7329
|
+
const candidates = [cwd, join10(cwd, "..")];
|
|
7166
7330
|
for (const dir of candidates) {
|
|
7167
|
-
const p =
|
|
7331
|
+
const p = join10(dir, "docker-compose.yml");
|
|
7168
7332
|
if (existsSync7(p)) return p;
|
|
7169
7333
|
}
|
|
7170
7334
|
return standalonePath;
|
|
@@ -7175,9 +7339,9 @@ var SetupManager = class {
|
|
|
7175
7339
|
* Always regenerates Docker files to keep passwords in sync.
|
|
7176
7340
|
*/
|
|
7177
7341
|
initConfig() {
|
|
7178
|
-
const dataDir =
|
|
7179
|
-
const configPath =
|
|
7180
|
-
const envPath =
|
|
7342
|
+
const dataDir = join10(homedir8(), ".agenticmail");
|
|
7343
|
+
const configPath = join10(dataDir, "config.json");
|
|
7344
|
+
const envPath = join10(dataDir, ".env");
|
|
7181
7345
|
if (existsSync7(configPath)) {
|
|
7182
7346
|
try {
|
|
7183
7347
|
const existing = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
@@ -7229,12 +7393,12 @@ IMAP_PORT=143
|
|
|
7229
7393
|
* with the correct admin password from config.
|
|
7230
7394
|
*/
|
|
7231
7395
|
generateDockerFiles(config) {
|
|
7232
|
-
const dataDir = config.dataDir ||
|
|
7396
|
+
const dataDir = config.dataDir || join10(homedir8(), ".agenticmail");
|
|
7233
7397
|
if (!existsSync7(dataDir)) {
|
|
7234
7398
|
mkdirSync6(dataDir, { recursive: true });
|
|
7235
7399
|
}
|
|
7236
7400
|
const password = config.stalwart?.adminPassword || "changeme";
|
|
7237
|
-
const composePath =
|
|
7401
|
+
const composePath = join10(dataDir, "docker-compose.yml");
|
|
7238
7402
|
writeFileSync5(composePath, `services:
|
|
7239
7403
|
stalwart:
|
|
7240
7404
|
# Pinned to v0.15.5 \u2014 Stalwart 0.16+ moved its config to JSON
|
|
@@ -7265,7 +7429,7 @@ volumes:
|
|
|
7265
7429
|
stalwart-data:
|
|
7266
7430
|
`);
|
|
7267
7431
|
chmodSync2(composePath, 384);
|
|
7268
|
-
const tomlPath =
|
|
7432
|
+
const tomlPath = join10(dataDir, "stalwart.toml");
|
|
7269
7433
|
writeFileSync5(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
|
|
7270
7434
|
|
|
7271
7435
|
[server]
|
|
@@ -7322,7 +7486,7 @@ secret = "${password}"
|
|
|
7322
7486
|
* Check if config has already been initialized.
|
|
7323
7487
|
*/
|
|
7324
7488
|
isInitialized() {
|
|
7325
|
-
const configPath =
|
|
7489
|
+
const configPath = join10(homedir8(), ".agenticmail", "config.json");
|
|
7326
7490
|
return existsSync7(configPath);
|
|
7327
7491
|
}
|
|
7328
7492
|
};
|
|
@@ -7330,7 +7494,7 @@ secret = "${password}"
|
|
|
7330
7494
|
// src/threading/thread-id.ts
|
|
7331
7495
|
import { createHash as createHash2 } from "crypto";
|
|
7332
7496
|
function stripReplyPrefixes(subject) {
|
|
7333
|
-
let s = subject;
|
|
7497
|
+
let s = subject.length > 1e3 ? subject.slice(0, 1e3) : subject;
|
|
7334
7498
|
for (; ; ) {
|
|
7335
7499
|
const next = s.replace(/^\s*(?:re|fwd?|fw)\s*(?:\[\d+\])?\s*:\s*/i, "");
|
|
7336
7500
|
if (next === s) break;
|
|
@@ -7350,8 +7514,9 @@ function normalizeSubject(subject) {
|
|
|
7350
7514
|
}
|
|
7351
7515
|
function normalizeAddress(addr) {
|
|
7352
7516
|
if (!addr) return "(unknown)";
|
|
7353
|
-
const
|
|
7354
|
-
const
|
|
7517
|
+
const bounded = addr.length > 500 ? addr.slice(0, 500) : addr;
|
|
7518
|
+
const m = bounded.match(/<([^>]+)>/);
|
|
7519
|
+
const raw = m ? m[1] : bounded;
|
|
7355
7520
|
return raw.trim().toLowerCase();
|
|
7356
7521
|
}
|
|
7357
7522
|
function threadIdFor(input) {
|
|
@@ -7371,8 +7536,8 @@ import {
|
|
|
7371
7536
|
renameSync
|
|
7372
7537
|
} from "fs";
|
|
7373
7538
|
import { homedir as homedir9 } from "os";
|
|
7374
|
-
import { join as
|
|
7375
|
-
var CACHE_DIR_DEFAULT =
|
|
7539
|
+
import { join as join11 } from "path";
|
|
7540
|
+
var CACHE_DIR_DEFAULT = join11(homedir9(), ".agenticmail", "thread-cache");
|
|
7376
7541
|
var DEFAULT_K_MESSAGES = 10;
|
|
7377
7542
|
var DEFAULT_LRU_CAP = 5e3;
|
|
7378
7543
|
var PREVIEW_MAX_CHARS = 240;
|
|
@@ -7390,7 +7555,7 @@ var ThreadCache = class {
|
|
|
7390
7555
|
}
|
|
7391
7556
|
}
|
|
7392
7557
|
pathFor(threadId) {
|
|
7393
|
-
return
|
|
7558
|
+
return join11(this.dir, `${threadId}.json`);
|
|
7394
7559
|
}
|
|
7395
7560
|
read(threadId) {
|
|
7396
7561
|
const p = this.pathFor(threadId);
|
|
@@ -7480,7 +7645,7 @@ var ThreadCache = class {
|
|
|
7480
7645
|
}
|
|
7481
7646
|
if (files.length <= this.lruCap) return;
|
|
7482
7647
|
const stats = files.map((f) => {
|
|
7483
|
-
const p =
|
|
7648
|
+
const p = join11(this.dir, f);
|
|
7484
7649
|
try {
|
|
7485
7650
|
return { p, mtime: statSync(p).mtimeMs };
|
|
7486
7651
|
} catch {
|
|
@@ -7519,8 +7684,8 @@ import {
|
|
|
7519
7684
|
renameSync as renameSync2
|
|
7520
7685
|
} from "fs";
|
|
7521
7686
|
import { homedir as homedir10 } from "os";
|
|
7522
|
-
import { join as
|
|
7523
|
-
var MEMORY_DIR_DEFAULT =
|
|
7687
|
+
import { join as join12 } from "path";
|
|
7688
|
+
var MEMORY_DIR_DEFAULT = join12(homedir10(), ".agenticmail", "agent-memory");
|
|
7524
7689
|
var AgentMemoryStore = class {
|
|
7525
7690
|
dir;
|
|
7526
7691
|
constructor(opts = {}) {
|
|
@@ -7531,10 +7696,10 @@ var AgentMemoryStore = class {
|
|
|
7531
7696
|
}
|
|
7532
7697
|
}
|
|
7533
7698
|
dirFor(agentId) {
|
|
7534
|
-
return
|
|
7699
|
+
return join12(this.dir, sanitizeId(agentId));
|
|
7535
7700
|
}
|
|
7536
7701
|
pathFor(agentId, threadId) {
|
|
7537
|
-
return
|
|
7702
|
+
return join12(this.dirFor(agentId), `${sanitizeId(threadId)}.md`);
|
|
7538
7703
|
}
|
|
7539
7704
|
read(agentId, threadId) {
|
|
7540
7705
|
const p = this.pathFor(agentId, threadId);
|
|
@@ -7635,6 +7800,8 @@ export {
|
|
|
7635
7800
|
InboxWatcher,
|
|
7636
7801
|
MailReceiver,
|
|
7637
7802
|
MailSender,
|
|
7803
|
+
PathTraversalError,
|
|
7804
|
+
REDACTED,
|
|
7638
7805
|
RELAY_PRESETS,
|
|
7639
7806
|
RelayBridge,
|
|
7640
7807
|
RelayGateway,
|
|
@@ -7646,7 +7813,10 @@ export {
|
|
|
7646
7813
|
StalwartAdmin,
|
|
7647
7814
|
ThreadCache,
|
|
7648
7815
|
TunnelManager,
|
|
7816
|
+
UnsafeApiUrlError,
|
|
7649
7817
|
WARNING_THRESHOLD,
|
|
7818
|
+
assertWithinBase,
|
|
7819
|
+
buildApiUrl,
|
|
7650
7820
|
buildInboundSecurityAdvisory,
|
|
7651
7821
|
classifyEmailRoute,
|
|
7652
7822
|
closeDatabase,
|
|
@@ -7665,12 +7835,17 @@ export {
|
|
|
7665
7835
|
parseEmail,
|
|
7666
7836
|
parseGoogleVoiceSms,
|
|
7667
7837
|
recordToolCall,
|
|
7838
|
+
redactObject,
|
|
7839
|
+
redactSecret,
|
|
7668
7840
|
resolveConfig,
|
|
7841
|
+
safeJoin,
|
|
7669
7842
|
sanitizeEmail,
|
|
7670
7843
|
saveConfig,
|
|
7671
7844
|
scanOutboundEmail,
|
|
7672
7845
|
scoreEmail,
|
|
7673
7846
|
setTelemetryVersion,
|
|
7674
7847
|
startRelayBridge,
|
|
7675
|
-
threadIdFor
|
|
7848
|
+
threadIdFor,
|
|
7849
|
+
tryJoin,
|
|
7850
|
+
validateApiUrl
|
|
7676
7851
|
};
|