@agenticmail/core 0.9.4 → 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 +270 -91
- package/dist/index.d.cts +249 -1
- package/dist/index.d.ts +249 -1
- package/dist/index.js +259 -90
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -726,6 +726,8 @@ __export(index_exports, {
|
|
|
726
726
|
InboxWatcher: () => InboxWatcher,
|
|
727
727
|
MailReceiver: () => MailReceiver,
|
|
728
728
|
MailSender: () => MailSender,
|
|
729
|
+
PathTraversalError: () => PathTraversalError,
|
|
730
|
+
REDACTED: () => REDACTED,
|
|
729
731
|
RELAY_PRESETS: () => RELAY_PRESETS,
|
|
730
732
|
RelayBridge: () => RelayBridge,
|
|
731
733
|
RelayGateway: () => RelayGateway,
|
|
@@ -737,7 +739,10 @@ __export(index_exports, {
|
|
|
737
739
|
StalwartAdmin: () => StalwartAdmin,
|
|
738
740
|
ThreadCache: () => ThreadCache,
|
|
739
741
|
TunnelManager: () => TunnelManager,
|
|
742
|
+
UnsafeApiUrlError: () => UnsafeApiUrlError,
|
|
740
743
|
WARNING_THRESHOLD: () => WARNING_THRESHOLD,
|
|
744
|
+
assertWithinBase: () => assertWithinBase,
|
|
745
|
+
buildApiUrl: () => buildApiUrl,
|
|
741
746
|
buildInboundSecurityAdvisory: () => buildInboundSecurityAdvisory,
|
|
742
747
|
classifyEmailRoute: () => classifyEmailRoute,
|
|
743
748
|
closeDatabase: () => closeDatabase,
|
|
@@ -756,14 +761,19 @@ __export(index_exports, {
|
|
|
756
761
|
parseEmail: () => parseEmail,
|
|
757
762
|
parseGoogleVoiceSms: () => parseGoogleVoiceSms,
|
|
758
763
|
recordToolCall: () => recordToolCall,
|
|
764
|
+
redactObject: () => redactObject,
|
|
765
|
+
redactSecret: () => redactSecret,
|
|
759
766
|
resolveConfig: () => resolveConfig,
|
|
767
|
+
safeJoin: () => safeJoin,
|
|
760
768
|
sanitizeEmail: () => sanitizeEmail,
|
|
761
769
|
saveConfig: () => saveConfig,
|
|
762
770
|
scanOutboundEmail: () => scanOutboundEmail,
|
|
763
771
|
scoreEmail: () => scoreEmail,
|
|
764
772
|
setTelemetryVersion: () => setTelemetryVersion,
|
|
765
773
|
startRelayBridge: () => startRelayBridge,
|
|
766
|
-
threadIdFor: () => threadIdFor
|
|
774
|
+
threadIdFor: () => threadIdFor,
|
|
775
|
+
tryJoin: () => tryJoin,
|
|
776
|
+
validateApiUrl: () => validateApiUrl
|
|
767
777
|
});
|
|
768
778
|
module.exports = __toCommonJS(index_exports);
|
|
769
779
|
|
|
@@ -837,7 +847,7 @@ var MailSender = class {
|
|
|
837
847
|
const code = err?.responseCode ?? err?.code;
|
|
838
848
|
const isTransient = typeof code === "number" && code >= 400 && code < 500 || code === "ECONNRESET" || code === "ETIMEDOUT" || code === "ESOCKET";
|
|
839
849
|
if (!isTransient || attempt === MAX_RETRIES) throw err;
|
|
840
|
-
await new Promise((
|
|
850
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1e3 * (attempt + 1)));
|
|
841
851
|
}
|
|
842
852
|
}
|
|
843
853
|
throw lastError;
|
|
@@ -1769,20 +1779,20 @@ var StalwartAdmin = class {
|
|
|
1769
1779
|
}
|
|
1770
1780
|
try {
|
|
1771
1781
|
const net = await import("net");
|
|
1772
|
-
return await new Promise((
|
|
1782
|
+
return await new Promise((resolve2) => {
|
|
1773
1783
|
const smtpPort = parseInt(process.env.SMTP_PORT || "25", 10);
|
|
1774
1784
|
const smtpHost = process.env.SMTP_HOST || "localhost";
|
|
1775
1785
|
const socket = net.createConnection({ host: smtpHost, port: smtpPort, timeout: 3e3 }, () => {
|
|
1776
1786
|
socket.destroy();
|
|
1777
|
-
|
|
1787
|
+
resolve2(true);
|
|
1778
1788
|
});
|
|
1779
1789
|
socket.on("error", () => {
|
|
1780
1790
|
socket.destroy();
|
|
1781
|
-
|
|
1791
|
+
resolve2(false);
|
|
1782
1792
|
});
|
|
1783
1793
|
socket.on("timeout", () => {
|
|
1784
1794
|
socket.destroy();
|
|
1785
|
-
|
|
1795
|
+
resolve2(false);
|
|
1786
1796
|
});
|
|
1787
1797
|
});
|
|
1788
1798
|
} catch {
|
|
@@ -1854,8 +1864,8 @@ var StalwartAdmin = class {
|
|
|
1854
1864
|
}
|
|
1855
1865
|
const { readFileSync: readFileSync7, writeFileSync: writeFileSync8 } = await import("fs");
|
|
1856
1866
|
const { homedir: homedir11 } = await import("os");
|
|
1857
|
-
const { join:
|
|
1858
|
-
const configPath =
|
|
1867
|
+
const { join: join13 } = await import("path");
|
|
1868
|
+
const configPath = join13(homedir11(), ".agenticmail", "stalwart.toml");
|
|
1859
1869
|
try {
|
|
1860
1870
|
let config = readFileSync7(configPath, "utf-8");
|
|
1861
1871
|
config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
|
|
@@ -1869,14 +1879,14 @@ var StalwartAdmin = class {
|
|
|
1869
1879
|
/** Path to the host-side stalwart.toml (mounted read-only into container) */
|
|
1870
1880
|
get configPath() {
|
|
1871
1881
|
const { homedir: homedir11 } = require("os");
|
|
1872
|
-
const { join:
|
|
1873
|
-
return
|
|
1882
|
+
const { join: join13 } = require("path");
|
|
1883
|
+
return join13(homedir11(), ".agenticmail", "stalwart.toml");
|
|
1874
1884
|
}
|
|
1875
1885
|
/** Path to host-side DKIM key directory */
|
|
1876
1886
|
get dkimDir() {
|
|
1877
1887
|
const { homedir: homedir11 } = require("os");
|
|
1878
|
-
const { join:
|
|
1879
|
-
return
|
|
1888
|
+
const { join: join13 } = require("path");
|
|
1889
|
+
return join13(homedir11(), ".agenticmail");
|
|
1880
1890
|
}
|
|
1881
1891
|
/**
|
|
1882
1892
|
* Create/reuse a DKIM signing key for a domain.
|
|
@@ -1979,9 +1989,9 @@ var StalwartAdmin = class {
|
|
|
1979
1989
|
async configureOutboundRelay(config) {
|
|
1980
1990
|
const { readFileSync: readFileSync7, writeFileSync: writeFileSync8 } = await import("fs");
|
|
1981
1991
|
const { homedir: homedir11 } = await import("os");
|
|
1982
|
-
const { join:
|
|
1992
|
+
const { join: join13 } = await import("path");
|
|
1983
1993
|
const routeName = config.routeName ?? "gmail";
|
|
1984
|
-
const tomlPath =
|
|
1994
|
+
const tomlPath = join13(homedir11(), ".agenticmail", "stalwart.toml");
|
|
1985
1995
|
let toml = readFileSync7(tomlPath, "utf-8");
|
|
1986
1996
|
toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
|
|
1987
1997
|
toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
|
|
@@ -3089,7 +3099,8 @@ var OUTBOUND_TEXT_RULES = [
|
|
|
3089
3099
|
var HIGH_RISK_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".p12", ".pfx", ".env", ".credentials", ".keystore", ".jks", ".p8"]);
|
|
3090
3100
|
var MEDIUM_RISK_EXTENSIONS = /* @__PURE__ */ new Set([".db", ".sqlite", ".sqlite3", ".sql", ".csv", ".tsv", ".json", ".yml", ".yaml", ".conf", ".config", ".ini"]);
|
|
3091
3101
|
function stripHtmlTags(html) {
|
|
3092
|
-
|
|
3102
|
+
const bounded = html.length > 1048576 ? html.slice(0, 1048576) : html;
|
|
3103
|
+
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)));
|
|
3093
3104
|
}
|
|
3094
3105
|
var TEXT_SCANNABLE_TYPES = /* @__PURE__ */ new Set([
|
|
3095
3106
|
"text/plain",
|
|
@@ -4622,7 +4633,7 @@ var CloudflareClient = class {
|
|
|
4622
4633
|
// --- Workers methods ---
|
|
4623
4634
|
/** Deploy an Email Worker script (ES module format) */
|
|
4624
4635
|
async deployEmailWorker(scriptName, scriptContent, envVars = {}) {
|
|
4625
|
-
const url = `${CF_API_BASE}/accounts/${this.accountId}/workers/scripts/${scriptName}`;
|
|
4636
|
+
const url = `${CF_API_BASE}/accounts/${encodeURIComponent(this.accountId)}/workers/scripts/${encodeURIComponent(scriptName)}`;
|
|
4626
4637
|
const bindings = Object.entries(envVars).map(([name, text2]) => ({
|
|
4627
4638
|
type: "plain_text",
|
|
4628
4639
|
name,
|
|
@@ -5040,7 +5051,7 @@ var TunnelManager = class {
|
|
|
5040
5051
|
detached: false,
|
|
5041
5052
|
env: { ...process.env, TUNNEL_TOKEN: tunnelToken }
|
|
5042
5053
|
});
|
|
5043
|
-
await new Promise((
|
|
5054
|
+
await new Promise((resolve2, reject) => {
|
|
5044
5055
|
let resolved = false;
|
|
5045
5056
|
const timeout = setTimeout(() => {
|
|
5046
5057
|
if (!resolved) {
|
|
@@ -5054,7 +5065,7 @@ var TunnelManager = class {
|
|
|
5054
5065
|
resolved = true;
|
|
5055
5066
|
clearTimeout(timeout);
|
|
5056
5067
|
this.running = true;
|
|
5057
|
-
|
|
5068
|
+
resolve2();
|
|
5058
5069
|
}
|
|
5059
5070
|
};
|
|
5060
5071
|
this.process.stderr?.on("data", onData);
|
|
@@ -5093,8 +5104,8 @@ var TunnelManager = class {
|
|
|
5093
5104
|
this.process = null;
|
|
5094
5105
|
p.kill("SIGTERM");
|
|
5095
5106
|
await Promise.race([
|
|
5096
|
-
new Promise((
|
|
5097
|
-
new Promise((
|
|
5107
|
+
new Promise((resolve2) => p.on("exit", () => resolve2())),
|
|
5108
|
+
new Promise((resolve2) => setTimeout(resolve2, 5e3))
|
|
5098
5109
|
]);
|
|
5099
5110
|
this.running = false;
|
|
5100
5111
|
}
|
|
@@ -5150,7 +5161,10 @@ function parseGoogleVoiceSms(emailBody, emailFrom) {
|
|
|
5150
5161
|
if (!emailBody || typeof emailBody !== "string") return null;
|
|
5151
5162
|
if (!emailFrom || typeof emailFrom !== "string") return null;
|
|
5152
5163
|
const fromLower = emailFrom.toLowerCase();
|
|
5153
|
-
const
|
|
5164
|
+
const atIdx = fromLower.lastIndexOf("@");
|
|
5165
|
+
const domain = atIdx >= 0 ? fromLower.slice(atIdx + 1).replace(/[>"'\s].*$/, "") : "";
|
|
5166
|
+
const isGoogleDomain = domain === "google.com" || domain.endsWith(".google.com");
|
|
5167
|
+
const isGoogleVoice = isGoogleDomain && (fromLower.startsWith("voice-noreply@") || domain === "txt.voice.google.com" || domain === "voice.google.com" || domain.endsWith(".voice.google.com") || fromLower.includes("voice"));
|
|
5154
5168
|
if (!isGoogleVoice) return null;
|
|
5155
5169
|
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();
|
|
5156
5170
|
let from = "";
|
|
@@ -6181,6 +6195,15 @@ var GatewayManager = class {
|
|
|
6181
6195
|
bcc: mail.bcc ? Array.isArray(mail.bcc) ? mail.bcc.join(", ") : mail.bcc : void 0,
|
|
6182
6196
|
subject: mail.subject,
|
|
6183
6197
|
text: mail.text || void 0,
|
|
6198
|
+
// The `html` field is the literal HTML body of the outbound
|
|
6199
|
+
// mail — by design it is whatever the sender chose to compose.
|
|
6200
|
+
// CodeQL `js/xss` flags this because the value flows from user
|
|
6201
|
+
// input, but nodemailer is the SMTP serializer, not an HTML
|
|
6202
|
+
// renderer; XSS would only occur if the recipient's MUA
|
|
6203
|
+
// executed the body, which is outside our trust boundary.
|
|
6204
|
+
// The outbound-guard (packages/core/src/mail/outbound-guard.ts)
|
|
6205
|
+
// already scores HTML bodies for suspicious patterns at the
|
|
6206
|
+
// pre-send step. lgtm[js/xss]
|
|
6184
6207
|
html: mail.html || void 0,
|
|
6185
6208
|
replyTo: mail.replyTo || from,
|
|
6186
6209
|
inReplyTo: mail.inReplyTo || void 0,
|
|
@@ -6542,11 +6565,11 @@ var RelayBridge = class {
|
|
|
6542
6565
|
this.options = options;
|
|
6543
6566
|
}
|
|
6544
6567
|
async start() {
|
|
6545
|
-
return new Promise((
|
|
6568
|
+
return new Promise((resolve2, reject) => {
|
|
6546
6569
|
this.server = (0, import_node_http.createServer)((req, res) => this.handleRequest(req, res));
|
|
6547
6570
|
this.server.listen(this.options.port, "127.0.0.1", () => {
|
|
6548
6571
|
console.log(`[RelayBridge] Listening on 127.0.0.1:${this.options.port}`);
|
|
6549
|
-
|
|
6572
|
+
resolve2();
|
|
6550
6573
|
});
|
|
6551
6574
|
this.server.on("error", reject);
|
|
6552
6575
|
});
|
|
@@ -6748,16 +6771,161 @@ try {
|
|
|
6748
6771
|
} catch {
|
|
6749
6772
|
}
|
|
6750
6773
|
|
|
6774
|
+
// src/util/safe-path.ts
|
|
6775
|
+
var import_node_path5 = require("path");
|
|
6776
|
+
var PathTraversalError = class extends Error {
|
|
6777
|
+
constructor(baseDir, parts) {
|
|
6778
|
+
super(
|
|
6779
|
+
`path traversal attempt: ${JSON.stringify(parts)} resolves outside ${baseDir}`
|
|
6780
|
+
);
|
|
6781
|
+
this.baseDir = baseDir;
|
|
6782
|
+
this.parts = parts;
|
|
6783
|
+
this.name = "PathTraversalError";
|
|
6784
|
+
}
|
|
6785
|
+
};
|
|
6786
|
+
function safeJoin(baseDir, ...partsAndOpts) {
|
|
6787
|
+
let opts = {};
|
|
6788
|
+
const parts = [];
|
|
6789
|
+
for (const p of partsAndOpts) {
|
|
6790
|
+
if (typeof p === "string") {
|
|
6791
|
+
parts.push(p);
|
|
6792
|
+
} else if (p && typeof p === "object") {
|
|
6793
|
+
opts = p;
|
|
6794
|
+
}
|
|
6795
|
+
}
|
|
6796
|
+
if (!opts.allowAbsolute) {
|
|
6797
|
+
for (const part of parts) {
|
|
6798
|
+
if ((0, import_node_path5.isAbsolute)(part)) {
|
|
6799
|
+
throw new PathTraversalError(baseDir, parts);
|
|
6800
|
+
}
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
const resolvedBase = (0, import_node_path5.resolve)(baseDir);
|
|
6804
|
+
const resolved = (0, import_node_path5.resolve)(resolvedBase, ...parts);
|
|
6805
|
+
if (resolved !== resolvedBase && !resolved.startsWith(resolvedBase + import_node_path5.sep)) {
|
|
6806
|
+
throw new PathTraversalError(baseDir, parts);
|
|
6807
|
+
}
|
|
6808
|
+
return resolved;
|
|
6809
|
+
}
|
|
6810
|
+
function tryJoin(baseDir, ...parts) {
|
|
6811
|
+
try {
|
|
6812
|
+
return safeJoin(baseDir, ...parts);
|
|
6813
|
+
} catch (err) {
|
|
6814
|
+
if (err instanceof PathTraversalError) return null;
|
|
6815
|
+
throw err;
|
|
6816
|
+
}
|
|
6817
|
+
}
|
|
6818
|
+
function assertWithinBase(baseDir, candidate) {
|
|
6819
|
+
const resolvedBase = (0, import_node_path5.resolve)(baseDir);
|
|
6820
|
+
const resolvedCandidate = (0, import_node_path5.resolve)(candidate);
|
|
6821
|
+
if (resolvedCandidate !== resolvedBase && !resolvedCandidate.startsWith(resolvedBase + import_node_path5.sep)) {
|
|
6822
|
+
throw new PathTraversalError(baseDir, [candidate]);
|
|
6823
|
+
}
|
|
6824
|
+
return resolvedCandidate;
|
|
6825
|
+
}
|
|
6826
|
+
|
|
6827
|
+
// src/util/redact.ts
|
|
6828
|
+
var REDACTED = "***";
|
|
6829
|
+
function redactSecret(value) {
|
|
6830
|
+
if (typeof value !== "string") return REDACTED;
|
|
6831
|
+
if (value.length === 0) return REDACTED;
|
|
6832
|
+
for (const prefix of ["mk_", "ak_", "sk-", "pk_", "tok_"]) {
|
|
6833
|
+
if (value.startsWith(prefix)) return `${prefix}${REDACTED}`;
|
|
6834
|
+
}
|
|
6835
|
+
return REDACTED;
|
|
6836
|
+
}
|
|
6837
|
+
var SENSITIVE_KEY_PATTERNS = [
|
|
6838
|
+
/key$/i,
|
|
6839
|
+
/secret/i,
|
|
6840
|
+
/password/i,
|
|
6841
|
+
/passwd/i,
|
|
6842
|
+
/token/i,
|
|
6843
|
+
/authorization/i,
|
|
6844
|
+
/bearer/i,
|
|
6845
|
+
/\bapikey\b/i,
|
|
6846
|
+
/\bapi_key\b/i,
|
|
6847
|
+
/\bmasterkey\b/i,
|
|
6848
|
+
/\bmaster_key\b/i
|
|
6849
|
+
];
|
|
6850
|
+
function looksSensitive(key) {
|
|
6851
|
+
return SENSITIVE_KEY_PATTERNS.some((p) => p.test(key));
|
|
6852
|
+
}
|
|
6853
|
+
function redactObject(input, _depth = 0) {
|
|
6854
|
+
if (_depth > 12) return input;
|
|
6855
|
+
if (input === null || input === void 0) return input;
|
|
6856
|
+
if (typeof input !== "object") return input;
|
|
6857
|
+
if (Array.isArray(input)) {
|
|
6858
|
+
return input.map((v) => redactObject(v, _depth + 1));
|
|
6859
|
+
}
|
|
6860
|
+
const proto = Object.getPrototypeOf(input);
|
|
6861
|
+
if (proto !== Object.prototype && proto !== null) return input;
|
|
6862
|
+
const out = {};
|
|
6863
|
+
for (const [k, v] of Object.entries(input)) {
|
|
6864
|
+
if (looksSensitive(k)) {
|
|
6865
|
+
out[k] = typeof v === "string" ? redactSecret(v) : REDACTED;
|
|
6866
|
+
} else {
|
|
6867
|
+
out[k] = redactObject(v, _depth + 1);
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
return out;
|
|
6871
|
+
}
|
|
6872
|
+
|
|
6873
|
+
// src/util/safe-url.ts
|
|
6874
|
+
var UnsafeApiUrlError = class extends Error {
|
|
6875
|
+
constructor(raw, reason) {
|
|
6876
|
+
super(`unsafe AgenticMail API URL ${JSON.stringify(raw)}: ${reason}`);
|
|
6877
|
+
this.raw = raw;
|
|
6878
|
+
this.reason = reason;
|
|
6879
|
+
this.name = "UnsafeApiUrlError";
|
|
6880
|
+
}
|
|
6881
|
+
};
|
|
6882
|
+
var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
|
|
6883
|
+
"169.254.169.254",
|
|
6884
|
+
// AWS / Azure / GCP IPv4 metadata
|
|
6885
|
+
"fd00:ec2::254",
|
|
6886
|
+
// AWS IPv6 metadata
|
|
6887
|
+
"metadata.google.internal",
|
|
6888
|
+
// GCP DNS
|
|
6889
|
+
"metadata.azure.internal"
|
|
6890
|
+
// Azure DNS
|
|
6891
|
+
]);
|
|
6892
|
+
function validateApiUrl(raw) {
|
|
6893
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
6894
|
+
throw new UnsafeApiUrlError(String(raw), "must be a non-empty string");
|
|
6895
|
+
}
|
|
6896
|
+
let parsed;
|
|
6897
|
+
try {
|
|
6898
|
+
parsed = new URL(raw);
|
|
6899
|
+
} catch (err) {
|
|
6900
|
+
throw new UnsafeApiUrlError(raw, `unparseable: ${err.message}`);
|
|
6901
|
+
}
|
|
6902
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
6903
|
+
throw new UnsafeApiUrlError(raw, `unsupported protocol: ${parsed.protocol}`);
|
|
6904
|
+
}
|
|
6905
|
+
const host = parsed.hostname.toLowerCase().replace(/\.$/, "");
|
|
6906
|
+
if (BLOCKED_HOSTS.has(host)) {
|
|
6907
|
+
throw new UnsafeApiUrlError(raw, `blocked metadata host: ${host}`);
|
|
6908
|
+
}
|
|
6909
|
+
if (parsed.username || parsed.password) {
|
|
6910
|
+
throw new UnsafeApiUrlError(raw, "embedded credentials are not supported");
|
|
6911
|
+
}
|
|
6912
|
+
return parsed.origin;
|
|
6913
|
+
}
|
|
6914
|
+
function buildApiUrl(baseOrigin, pathAndQuery) {
|
|
6915
|
+
const path = pathAndQuery.startsWith("/") ? pathAndQuery : `/${pathAndQuery}`;
|
|
6916
|
+
return new URL(path, baseOrigin + "/").toString();
|
|
6917
|
+
}
|
|
6918
|
+
|
|
6751
6919
|
// src/setup/index.ts
|
|
6752
6920
|
var import_node_crypto3 = require("crypto");
|
|
6753
6921
|
var import_node_fs7 = require("fs");
|
|
6754
|
-
var
|
|
6922
|
+
var import_node_path9 = require("path");
|
|
6755
6923
|
var import_node_os7 = require("os");
|
|
6756
6924
|
|
|
6757
6925
|
// src/setup/deps.ts
|
|
6758
6926
|
var import_node_child_process2 = require("child_process");
|
|
6759
6927
|
var import_node_fs4 = require("fs");
|
|
6760
|
-
var
|
|
6928
|
+
var import_node_path6 = require("path");
|
|
6761
6929
|
var import_node_os4 = require("os");
|
|
6762
6930
|
var DependencyChecker = class {
|
|
6763
6931
|
async checkAll() {
|
|
@@ -6808,7 +6976,7 @@ var DependencyChecker = class {
|
|
|
6808
6976
|
}
|
|
6809
6977
|
}
|
|
6810
6978
|
async checkCloudflared() {
|
|
6811
|
-
const binPath = (0,
|
|
6979
|
+
const binPath = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".agenticmail", "bin", "cloudflared");
|
|
6812
6980
|
if ((0, import_node_fs4.existsSync)(binPath)) {
|
|
6813
6981
|
let version;
|
|
6814
6982
|
try {
|
|
@@ -6833,12 +7001,12 @@ var DependencyChecker = class {
|
|
|
6833
7001
|
var import_node_child_process3 = require("child_process");
|
|
6834
7002
|
var import_node_fs5 = require("fs");
|
|
6835
7003
|
var import_promises2 = require("fs/promises");
|
|
6836
|
-
var
|
|
7004
|
+
var import_node_path7 = require("path");
|
|
6837
7005
|
var import_node_os5 = require("os");
|
|
6838
7006
|
function runShellWithRollingOutput(cmd, opts = {}) {
|
|
6839
7007
|
const maxLines = opts.maxLines ?? 20;
|
|
6840
7008
|
const timeout = opts.timeout ?? 3e5;
|
|
6841
|
-
return new Promise((
|
|
7009
|
+
return new Promise((resolve2, reject) => {
|
|
6842
7010
|
const child = (0, import_node_child_process3.spawn)("sh", ["-c", cmd], {
|
|
6843
7011
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6844
7012
|
timeout
|
|
@@ -6880,7 +7048,7 @@ function runShellWithRollingOutput(cmd, opts = {}) {
|
|
|
6880
7048
|
}
|
|
6881
7049
|
process.stdout.write(`\x1B[${displayedCount}A`);
|
|
6882
7050
|
}
|
|
6883
|
-
|
|
7051
|
+
resolve2({ exitCode: code ?? 1, fullOutput });
|
|
6884
7052
|
});
|
|
6885
7053
|
child.on("error", (err) => {
|
|
6886
7054
|
if (displayedCount > 0) {
|
|
@@ -6896,7 +7064,7 @@ function runShellWithRollingOutput(cmd, opts = {}) {
|
|
|
6896
7064
|
}
|
|
6897
7065
|
function runSilent(command, args, opts = {}) {
|
|
6898
7066
|
const timeout = opts.timeout ?? 3e5;
|
|
6899
|
-
return new Promise((
|
|
7067
|
+
return new Promise((resolve2, reject) => {
|
|
6900
7068
|
const child = (0, import_node_child_process3.spawn)(command, args, {
|
|
6901
7069
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6902
7070
|
timeout
|
|
@@ -6908,7 +7076,7 @@ function runSilent(command, args, opts = {}) {
|
|
|
6908
7076
|
child.stderr?.on("data", (d) => {
|
|
6909
7077
|
fullOutput += d.toString();
|
|
6910
7078
|
});
|
|
6911
|
-
child.on("close", (code) =>
|
|
7079
|
+
child.on("close", (code) => resolve2({ exitCode: code ?? 1, fullOutput }));
|
|
6912
7080
|
child.on("error", reject);
|
|
6913
7081
|
});
|
|
6914
7082
|
}
|
|
@@ -7010,8 +7178,8 @@ var DependencyInstaller = class {
|
|
|
7010
7178
|
try {
|
|
7011
7179
|
const composeBin = (0, import_node_child_process3.execFileSync)("which", ["docker-compose"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
7012
7180
|
if (!composeBin) return;
|
|
7013
|
-
const pluginDir = (0,
|
|
7014
|
-
const pluginPath = (0,
|
|
7181
|
+
const pluginDir = (0, import_node_path7.join)((0, import_node_os5.homedir)(), ".docker", "cli-plugins");
|
|
7182
|
+
const pluginPath = (0, import_node_path7.join)(pluginDir, "docker-compose");
|
|
7015
7183
|
if ((0, import_node_fs5.existsSync)(pluginPath)) return;
|
|
7016
7184
|
try {
|
|
7017
7185
|
(0, import_node_fs5.mkdirSync)(pluginDir, { recursive: true });
|
|
@@ -7077,9 +7245,9 @@ var DependencyInstaller = class {
|
|
|
7077
7245
|
return;
|
|
7078
7246
|
}
|
|
7079
7247
|
this.onProgress("__progress__:5:Installing Docker Engine...");
|
|
7080
|
-
const tmpDir = (0,
|
|
7248
|
+
const tmpDir = (0, import_node_path7.join)((0, import_node_os5.homedir)(), ".agenticmail", "tmp");
|
|
7081
7249
|
await (0, import_promises2.mkdir)(tmpDir, { recursive: true });
|
|
7082
|
-
const scriptPath = (0,
|
|
7250
|
+
const scriptPath = (0, import_node_path7.join)(tmpDir, "install-docker.sh");
|
|
7083
7251
|
const dlResult = await runShellWithRollingOutput(
|
|
7084
7252
|
`curl -fsSL https://get.docker.com -o "${scriptPath}" && sudo sh "${scriptPath}"`,
|
|
7085
7253
|
{ timeout: 3e5 }
|
|
@@ -7147,7 +7315,7 @@ var DependencyInstaller = class {
|
|
|
7147
7315
|
}
|
|
7148
7316
|
try {
|
|
7149
7317
|
const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
|
|
7150
|
-
const dockerExe = (0,
|
|
7318
|
+
const dockerExe = (0, import_node_path7.join)(programFiles, "Docker", "Docker", "Docker Desktop.exe");
|
|
7151
7319
|
if ((0, import_node_fs5.existsSync)(dockerExe)) {
|
|
7152
7320
|
(0, import_node_child_process3.execSync)(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
|
|
7153
7321
|
}
|
|
@@ -7198,7 +7366,7 @@ var DependencyInstaller = class {
|
|
|
7198
7366
|
this.onProgress("__progress__:70:Docker Desktop installed. Starting...");
|
|
7199
7367
|
try {
|
|
7200
7368
|
const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
|
|
7201
|
-
const dockerExe = (0,
|
|
7369
|
+
const dockerExe = (0, import_node_path7.join)(programFiles, "Docker", "Docker", "Docker Desktop.exe");
|
|
7202
7370
|
if ((0, import_node_fs5.existsSync)(dockerExe)) {
|
|
7203
7371
|
(0, import_node_child_process3.execSync)(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
|
|
7204
7372
|
}
|
|
@@ -7295,9 +7463,9 @@ var DependencyInstaller = class {
|
|
|
7295
7463
|
*/
|
|
7296
7464
|
async installCloudflared() {
|
|
7297
7465
|
const os = (0, import_node_os5.platform)();
|
|
7298
|
-
const binDir = (0,
|
|
7466
|
+
const binDir = (0, import_node_path7.join)((0, import_node_os5.homedir)(), ".agenticmail", "bin");
|
|
7299
7467
|
const binName = os === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
7300
|
-
const binPath = (0,
|
|
7468
|
+
const binPath = (0, import_node_path7.join)(binDir, binName);
|
|
7301
7469
|
if ((0, import_node_fs5.existsSync)(binPath)) {
|
|
7302
7470
|
return binPath;
|
|
7303
7471
|
}
|
|
@@ -7327,7 +7495,7 @@ var DependencyInstaller = class {
|
|
|
7327
7495
|
}
|
|
7328
7496
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
7329
7497
|
if (os === "darwin") {
|
|
7330
|
-
const tgzPath = (0,
|
|
7498
|
+
const tgzPath = (0, import_node_path7.join)(binDir, "cloudflared.tgz");
|
|
7331
7499
|
await (0, import_promises2.writeFile)(tgzPath, buffer);
|
|
7332
7500
|
try {
|
|
7333
7501
|
(0, import_node_child_process3.execFileSync)("tar", ["-xzf", tgzPath, "-C", binDir, "cloudflared"], { timeout: 15e3, stdio: "ignore" });
|
|
@@ -7363,7 +7531,7 @@ var DependencyInstaller = class {
|
|
|
7363
7531
|
// src/setup/service.ts
|
|
7364
7532
|
var import_node_child_process4 = require("child_process");
|
|
7365
7533
|
var import_node_fs6 = require("fs");
|
|
7366
|
-
var
|
|
7534
|
+
var import_node_path8 = require("path");
|
|
7367
7535
|
var import_node_os6 = require("os");
|
|
7368
7536
|
var import_node_module2 = require("module");
|
|
7369
7537
|
var import_meta2 = {};
|
|
@@ -7376,9 +7544,9 @@ var ServiceManager = class {
|
|
|
7376
7544
|
*/
|
|
7377
7545
|
getServicePath() {
|
|
7378
7546
|
if (this.os === "darwin") {
|
|
7379
|
-
return (0,
|
|
7547
|
+
return (0, import_node_path8.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
7380
7548
|
} else {
|
|
7381
|
-
return (0,
|
|
7549
|
+
return (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
7382
7550
|
}
|
|
7383
7551
|
}
|
|
7384
7552
|
/**
|
|
@@ -7416,33 +7584,33 @@ var ServiceManager = class {
|
|
|
7416
7584
|
} catch {
|
|
7417
7585
|
}
|
|
7418
7586
|
const parentPackages = [
|
|
7419
|
-
(0,
|
|
7587
|
+
(0, import_node_path8.join)("@agenticmail", "cli"),
|
|
7420
7588
|
// current scoped package
|
|
7421
7589
|
"agenticmail"
|
|
7422
7590
|
// legacy unscoped package
|
|
7423
7591
|
];
|
|
7424
7592
|
const baseDirs = [
|
|
7425
7593
|
// user-local install
|
|
7426
|
-
(0,
|
|
7594
|
+
(0, import_node_path8.join)((0, import_node_os6.homedir)(), "node_modules")
|
|
7427
7595
|
];
|
|
7428
7596
|
try {
|
|
7429
7597
|
const prefix = (0, import_node_child_process4.execSync)("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
7430
|
-
baseDirs.push((0,
|
|
7431
|
-
baseDirs.push((0,
|
|
7598
|
+
baseDirs.push((0, import_node_path8.join)(prefix, "lib", "node_modules"));
|
|
7599
|
+
baseDirs.push((0, import_node_path8.join)(prefix, "node_modules"));
|
|
7432
7600
|
} catch {
|
|
7433
7601
|
}
|
|
7434
7602
|
baseDirs.push("/opt/homebrew/lib/node_modules");
|
|
7435
7603
|
baseDirs.push("/usr/local/lib/node_modules");
|
|
7436
7604
|
for (const base of baseDirs) {
|
|
7437
|
-
const sibling = (0,
|
|
7605
|
+
const sibling = (0, import_node_path8.join)(base, "@agenticmail", "api", "dist", "index.js");
|
|
7438
7606
|
if ((0, import_node_fs6.existsSync)(sibling)) return sibling;
|
|
7439
7607
|
for (const parent of parentPackages) {
|
|
7440
|
-
const nested = (0,
|
|
7608
|
+
const nested = (0, import_node_path8.join)(base, parent, "node_modules", "@agenticmail", "api", "dist", "index.js");
|
|
7441
7609
|
if ((0, import_node_fs6.existsSync)(nested)) return nested;
|
|
7442
7610
|
}
|
|
7443
7611
|
}
|
|
7444
|
-
const dataDir = (0,
|
|
7445
|
-
const entryCache = (0,
|
|
7612
|
+
const dataDir = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail");
|
|
7613
|
+
const entryCache = (0, import_node_path8.join)(dataDir, "api-entry.path");
|
|
7446
7614
|
if ((0, import_node_fs6.existsSync)(entryCache)) {
|
|
7447
7615
|
const cached = (0, import_node_fs6.readFileSync)(entryCache, "utf-8").trim();
|
|
7448
7616
|
if (cached && (0, import_node_fs6.existsSync)(cached)) return cached;
|
|
@@ -7453,9 +7621,9 @@ var ServiceManager = class {
|
|
|
7453
7621
|
* Cache the API entry path so the service can find it later.
|
|
7454
7622
|
*/
|
|
7455
7623
|
cacheApiEntryPath(entryPath) {
|
|
7456
|
-
const dataDir = (0,
|
|
7624
|
+
const dataDir = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail");
|
|
7457
7625
|
if (!(0, import_node_fs6.existsSync)(dataDir)) (0, import_node_fs6.mkdirSync)(dataDir, { recursive: true });
|
|
7458
|
-
(0, import_node_fs6.writeFileSync)((0,
|
|
7626
|
+
(0, import_node_fs6.writeFileSync)((0, import_node_path8.join)(dataDir, "api-entry.path"), entryPath);
|
|
7459
7627
|
}
|
|
7460
7628
|
/**
|
|
7461
7629
|
* Get the current package version.
|
|
@@ -7476,7 +7644,7 @@ var ServiceManager = class {
|
|
|
7476
7644
|
}
|
|
7477
7645
|
try {
|
|
7478
7646
|
const apiEntry = this.getApiEntryPath();
|
|
7479
|
-
const apiPkg = (0,
|
|
7647
|
+
const apiPkg = (0, import_node_path8.join)(apiEntry, "..", "..", "package.json");
|
|
7480
7648
|
if ((0, import_node_fs6.existsSync)(apiPkg)) {
|
|
7481
7649
|
const pkg = JSON.parse((0, import_node_fs6.readFileSync)(apiPkg, "utf-8"));
|
|
7482
7650
|
if (pkg.version) return pkg.version;
|
|
@@ -7484,14 +7652,14 @@ var ServiceManager = class {
|
|
|
7484
7652
|
} catch {
|
|
7485
7653
|
}
|
|
7486
7654
|
const candidates = [
|
|
7487
|
-
(0,
|
|
7488
|
-
(0,
|
|
7489
|
-
(0,
|
|
7655
|
+
(0, import_node_path8.join)((0, import_node_os6.homedir)(), "node_modules", "@agenticmail", "cli", "package.json"),
|
|
7656
|
+
(0, import_node_path8.join)((0, import_node_os6.homedir)(), "node_modules", "agenticmail", "package.json"),
|
|
7657
|
+
(0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail", "package-version.json")
|
|
7490
7658
|
];
|
|
7491
7659
|
try {
|
|
7492
7660
|
const prefix = (0, import_node_child_process4.execSync)("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
7493
|
-
candidates.push((0,
|
|
7494
|
-
candidates.push((0,
|
|
7661
|
+
candidates.push((0, import_node_path8.join)(prefix, "lib", "node_modules", "@agenticmail", "cli", "package.json"));
|
|
7662
|
+
candidates.push((0, import_node_path8.join)(prefix, "lib", "node_modules", "agenticmail", "package.json"));
|
|
7495
7663
|
} catch {
|
|
7496
7664
|
}
|
|
7497
7665
|
for (const p of candidates) {
|
|
@@ -7510,8 +7678,8 @@ var ServiceManager = class {
|
|
|
7510
7678
|
* This ensures AgenticMail doesn't fail on boot when Docker is still loading.
|
|
7511
7679
|
*/
|
|
7512
7680
|
generateStartScript(nodePath, apiEntry) {
|
|
7513
|
-
const scriptPath = (0,
|
|
7514
|
-
const scriptDir = (0,
|
|
7681
|
+
const scriptPath = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin", "start-server.sh");
|
|
7682
|
+
const scriptDir = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin");
|
|
7515
7683
|
if (!(0, import_node_fs6.existsSync)(scriptDir)) (0, import_node_fs6.mkdirSync)(scriptDir, { recursive: true });
|
|
7516
7684
|
const script = [
|
|
7517
7685
|
"#!/bin/bash",
|
|
@@ -7577,7 +7745,7 @@ var ServiceManager = class {
|
|
|
7577
7745
|
*/
|
|
7578
7746
|
generatePlist(nodePath, apiEntry, configPath) {
|
|
7579
7747
|
const config = JSON.parse((0, import_node_fs6.readFileSync)(configPath, "utf-8"));
|
|
7580
|
-
const logDir = (0,
|
|
7748
|
+
const logDir = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail", "logs");
|
|
7581
7749
|
if (!(0, import_node_fs6.existsSync)(logDir)) (0, import_node_fs6.mkdirSync)(logDir, { recursive: true });
|
|
7582
7750
|
const version = this.getVersion();
|
|
7583
7751
|
const startScript = this.generateStartScript(nodePath, apiEntry);
|
|
@@ -7601,7 +7769,7 @@ var ServiceManager = class {
|
|
|
7601
7769
|
<key>HOME</key>
|
|
7602
7770
|
<string>${(0, import_node_os6.homedir)()}</string>
|
|
7603
7771
|
<key>AGENTICMAIL_DATA_DIR</key>
|
|
7604
|
-
<string>${config.dataDir || (0,
|
|
7772
|
+
<string>${config.dataDir || (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail")}</string>
|
|
7605
7773
|
<key>PATH</key>
|
|
7606
7774
|
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
7607
7775
|
<key>AGENTICMAIL_SERVICE_VERSION</key>
|
|
@@ -7655,7 +7823,7 @@ var ServiceManager = class {
|
|
|
7655
7823
|
*/
|
|
7656
7824
|
generateSystemdUnit(nodePath, apiEntry, configPath) {
|
|
7657
7825
|
const config = JSON.parse((0, import_node_fs6.readFileSync)(configPath, "utf-8"));
|
|
7658
|
-
const dataDir = config.dataDir || (0,
|
|
7826
|
+
const dataDir = config.dataDir || (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail");
|
|
7659
7827
|
const version = this.getVersion();
|
|
7660
7828
|
const startScript = this.generateStartScript(nodePath, apiEntry);
|
|
7661
7829
|
return `[Unit]
|
|
@@ -7685,7 +7853,7 @@ WantedBy=default.target
|
|
|
7685
7853
|
* Install the auto-start service.
|
|
7686
7854
|
*/
|
|
7687
7855
|
install() {
|
|
7688
|
-
const configPath = (0,
|
|
7856
|
+
const configPath = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail", "config.json");
|
|
7689
7857
|
if (!(0, import_node_fs6.existsSync)(configPath)) {
|
|
7690
7858
|
return { installed: false, message: "Config not found. Run agenticmail setup first." };
|
|
7691
7859
|
}
|
|
@@ -7698,7 +7866,7 @@ WantedBy=default.target
|
|
|
7698
7866
|
}
|
|
7699
7867
|
const servicePath = this.getServicePath();
|
|
7700
7868
|
if (this.os === "darwin") {
|
|
7701
|
-
const dir = (0,
|
|
7869
|
+
const dir = (0, import_node_path8.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents");
|
|
7702
7870
|
if (!(0, import_node_fs6.existsSync)(dir)) (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
|
|
7703
7871
|
if ((0, import_node_fs6.existsSync)(servicePath)) {
|
|
7704
7872
|
try {
|
|
@@ -7716,7 +7884,7 @@ WantedBy=default.target
|
|
|
7716
7884
|
}
|
|
7717
7885
|
return { installed: true, message: `Service installed at ${servicePath}` };
|
|
7718
7886
|
} else if (this.os === "linux") {
|
|
7719
|
-
const dir = (0,
|
|
7887
|
+
const dir = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
|
|
7720
7888
|
if (!(0, import_node_fs6.existsSync)(dir)) (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
|
|
7721
7889
|
const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
|
|
7722
7890
|
(0, import_node_fs6.writeFileSync)(servicePath, unit);
|
|
@@ -7842,7 +8010,7 @@ WantedBy=default.target
|
|
|
7842
8010
|
} catch {
|
|
7843
8011
|
return { reason: "Service file unreadable" };
|
|
7844
8012
|
}
|
|
7845
|
-
const startScript = (0,
|
|
8013
|
+
const startScript = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin", "start-server.sh");
|
|
7846
8014
|
if (serviceContent.includes(startScript)) {
|
|
7847
8015
|
if (!(0, import_node_fs6.existsSync)(startScript)) {
|
|
7848
8016
|
return { reason: "start-server.sh is missing" };
|
|
@@ -7875,7 +8043,7 @@ WantedBy=default.target
|
|
|
7875
8043
|
return { reason: `Service version drift (current CLI is v${currentVersion})` };
|
|
7876
8044
|
}
|
|
7877
8045
|
}
|
|
7878
|
-
const entryCache = (0,
|
|
8046
|
+
const entryCache = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".agenticmail", "api-entry.path");
|
|
7879
8047
|
if ((0, import_node_fs6.existsSync)(entryCache)) {
|
|
7880
8048
|
try {
|
|
7881
8049
|
const cached = (0, import_node_fs6.readFileSync)(entryCache, "utf-8").trim();
|
|
@@ -7930,12 +8098,12 @@ var SetupManager = class {
|
|
|
7930
8098
|
* falls back to monorepo location.
|
|
7931
8099
|
*/
|
|
7932
8100
|
getComposePath() {
|
|
7933
|
-
const standalonePath = (0,
|
|
8101
|
+
const standalonePath = (0, import_node_path9.join)((0, import_node_os7.homedir)(), ".agenticmail", "docker-compose.yml");
|
|
7934
8102
|
if ((0, import_node_fs7.existsSync)(standalonePath)) return standalonePath;
|
|
7935
8103
|
const cwd = process.cwd();
|
|
7936
|
-
const candidates = [cwd, (0,
|
|
8104
|
+
const candidates = [cwd, (0, import_node_path9.join)(cwd, "..")];
|
|
7937
8105
|
for (const dir of candidates) {
|
|
7938
|
-
const p = (0,
|
|
8106
|
+
const p = (0, import_node_path9.join)(dir, "docker-compose.yml");
|
|
7939
8107
|
if ((0, import_node_fs7.existsSync)(p)) return p;
|
|
7940
8108
|
}
|
|
7941
8109
|
return standalonePath;
|
|
@@ -7946,9 +8114,9 @@ var SetupManager = class {
|
|
|
7946
8114
|
* Always regenerates Docker files to keep passwords in sync.
|
|
7947
8115
|
*/
|
|
7948
8116
|
initConfig() {
|
|
7949
|
-
const dataDir = (0,
|
|
7950
|
-
const configPath = (0,
|
|
7951
|
-
const envPath = (0,
|
|
8117
|
+
const dataDir = (0, import_node_path9.join)((0, import_node_os7.homedir)(), ".agenticmail");
|
|
8118
|
+
const configPath = (0, import_node_path9.join)(dataDir, "config.json");
|
|
8119
|
+
const envPath = (0, import_node_path9.join)(dataDir, ".env");
|
|
7952
8120
|
if ((0, import_node_fs7.existsSync)(configPath)) {
|
|
7953
8121
|
try {
|
|
7954
8122
|
const existing = JSON.parse((0, import_node_fs7.readFileSync)(configPath, "utf-8"));
|
|
@@ -8000,12 +8168,12 @@ IMAP_PORT=143
|
|
|
8000
8168
|
* with the correct admin password from config.
|
|
8001
8169
|
*/
|
|
8002
8170
|
generateDockerFiles(config) {
|
|
8003
|
-
const dataDir = config.dataDir || (0,
|
|
8171
|
+
const dataDir = config.dataDir || (0, import_node_path9.join)((0, import_node_os7.homedir)(), ".agenticmail");
|
|
8004
8172
|
if (!(0, import_node_fs7.existsSync)(dataDir)) {
|
|
8005
8173
|
(0, import_node_fs7.mkdirSync)(dataDir, { recursive: true });
|
|
8006
8174
|
}
|
|
8007
8175
|
const password = config.stalwart?.adminPassword || "changeme";
|
|
8008
|
-
const composePath = (0,
|
|
8176
|
+
const composePath = (0, import_node_path9.join)(dataDir, "docker-compose.yml");
|
|
8009
8177
|
(0, import_node_fs7.writeFileSync)(composePath, `services:
|
|
8010
8178
|
stalwart:
|
|
8011
8179
|
# Pinned to v0.15.5 \u2014 Stalwart 0.16+ moved its config to JSON
|
|
@@ -8036,7 +8204,7 @@ volumes:
|
|
|
8036
8204
|
stalwart-data:
|
|
8037
8205
|
`);
|
|
8038
8206
|
(0, import_node_fs7.chmodSync)(composePath, 384);
|
|
8039
|
-
const tomlPath = (0,
|
|
8207
|
+
const tomlPath = (0, import_node_path9.join)(dataDir, "stalwart.toml");
|
|
8040
8208
|
(0, import_node_fs7.writeFileSync)(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
|
|
8041
8209
|
|
|
8042
8210
|
[server]
|
|
@@ -8093,7 +8261,7 @@ secret = "${password}"
|
|
|
8093
8261
|
* Check if config has already been initialized.
|
|
8094
8262
|
*/
|
|
8095
8263
|
isInitialized() {
|
|
8096
|
-
const configPath = (0,
|
|
8264
|
+
const configPath = (0, import_node_path9.join)((0, import_node_os7.homedir)(), ".agenticmail", "config.json");
|
|
8097
8265
|
return (0, import_node_fs7.existsSync)(configPath);
|
|
8098
8266
|
}
|
|
8099
8267
|
};
|
|
@@ -8101,7 +8269,7 @@ secret = "${password}"
|
|
|
8101
8269
|
// src/threading/thread-id.ts
|
|
8102
8270
|
var import_node_crypto4 = require("crypto");
|
|
8103
8271
|
function stripReplyPrefixes(subject) {
|
|
8104
|
-
let s = subject;
|
|
8272
|
+
let s = subject.length > 1e3 ? subject.slice(0, 1e3) : subject;
|
|
8105
8273
|
for (; ; ) {
|
|
8106
8274
|
const next = s.replace(/^\s*(?:re|fwd?|fw)\s*(?:\[\d+\])?\s*:\s*/i, "");
|
|
8107
8275
|
if (next === s) break;
|
|
@@ -8121,8 +8289,9 @@ function normalizeSubject(subject) {
|
|
|
8121
8289
|
}
|
|
8122
8290
|
function normalizeAddress(addr) {
|
|
8123
8291
|
if (!addr) return "(unknown)";
|
|
8124
|
-
const
|
|
8125
|
-
const
|
|
8292
|
+
const bounded = addr.length > 500 ? addr.slice(0, 500) : addr;
|
|
8293
|
+
const m = bounded.match(/<([^>]+)>/);
|
|
8294
|
+
const raw = m ? m[1] : bounded;
|
|
8126
8295
|
return raw.trim().toLowerCase();
|
|
8127
8296
|
}
|
|
8128
8297
|
function threadIdFor(input) {
|
|
@@ -8133,8 +8302,8 @@ function threadIdFor(input) {
|
|
|
8133
8302
|
// src/threading/thread-cache.ts
|
|
8134
8303
|
var import_node_fs8 = require("fs");
|
|
8135
8304
|
var import_node_os8 = require("os");
|
|
8136
|
-
var
|
|
8137
|
-
var CACHE_DIR_DEFAULT = (0,
|
|
8305
|
+
var import_node_path10 = require("path");
|
|
8306
|
+
var CACHE_DIR_DEFAULT = (0, import_node_path10.join)((0, import_node_os8.homedir)(), ".agenticmail", "thread-cache");
|
|
8138
8307
|
var DEFAULT_K_MESSAGES = 10;
|
|
8139
8308
|
var DEFAULT_LRU_CAP = 5e3;
|
|
8140
8309
|
var PREVIEW_MAX_CHARS = 240;
|
|
@@ -8152,7 +8321,7 @@ var ThreadCache = class {
|
|
|
8152
8321
|
}
|
|
8153
8322
|
}
|
|
8154
8323
|
pathFor(threadId) {
|
|
8155
|
-
return (0,
|
|
8324
|
+
return (0, import_node_path10.join)(this.dir, `${threadId}.json`);
|
|
8156
8325
|
}
|
|
8157
8326
|
read(threadId) {
|
|
8158
8327
|
const p = this.pathFor(threadId);
|
|
@@ -8242,7 +8411,7 @@ var ThreadCache = class {
|
|
|
8242
8411
|
}
|
|
8243
8412
|
if (files.length <= this.lruCap) return;
|
|
8244
8413
|
const stats = files.map((f) => {
|
|
8245
|
-
const p = (0,
|
|
8414
|
+
const p = (0, import_node_path10.join)(this.dir, f);
|
|
8246
8415
|
try {
|
|
8247
8416
|
return { p, mtime: (0, import_node_fs8.statSync)(p).mtimeMs };
|
|
8248
8417
|
} catch {
|
|
@@ -8274,8 +8443,8 @@ function dedupAndCap(messages, k) {
|
|
|
8274
8443
|
// src/threading/agent-memory.ts
|
|
8275
8444
|
var import_node_fs9 = require("fs");
|
|
8276
8445
|
var import_node_os9 = require("os");
|
|
8277
|
-
var
|
|
8278
|
-
var MEMORY_DIR_DEFAULT = (0,
|
|
8446
|
+
var import_node_path11 = require("path");
|
|
8447
|
+
var MEMORY_DIR_DEFAULT = (0, import_node_path11.join)((0, import_node_os9.homedir)(), ".agenticmail", "agent-memory");
|
|
8279
8448
|
var AgentMemoryStore = class {
|
|
8280
8449
|
dir;
|
|
8281
8450
|
constructor(opts = {}) {
|
|
@@ -8286,10 +8455,10 @@ var AgentMemoryStore = class {
|
|
|
8286
8455
|
}
|
|
8287
8456
|
}
|
|
8288
8457
|
dirFor(agentId) {
|
|
8289
|
-
return (0,
|
|
8458
|
+
return (0, import_node_path11.join)(this.dir, sanitizeId(agentId));
|
|
8290
8459
|
}
|
|
8291
8460
|
pathFor(agentId, threadId) {
|
|
8292
|
-
return (0,
|
|
8461
|
+
return (0, import_node_path11.join)(this.dirFor(agentId), `${sanitizeId(threadId)}.md`);
|
|
8293
8462
|
}
|
|
8294
8463
|
read(agentId, threadId) {
|
|
8295
8464
|
const p = this.pathFor(agentId, threadId);
|
|
@@ -8391,6 +8560,8 @@ function parse(raw) {
|
|
|
8391
8560
|
InboxWatcher,
|
|
8392
8561
|
MailReceiver,
|
|
8393
8562
|
MailSender,
|
|
8563
|
+
PathTraversalError,
|
|
8564
|
+
REDACTED,
|
|
8394
8565
|
RELAY_PRESETS,
|
|
8395
8566
|
RelayBridge,
|
|
8396
8567
|
RelayGateway,
|
|
@@ -8402,7 +8573,10 @@ function parse(raw) {
|
|
|
8402
8573
|
StalwartAdmin,
|
|
8403
8574
|
ThreadCache,
|
|
8404
8575
|
TunnelManager,
|
|
8576
|
+
UnsafeApiUrlError,
|
|
8405
8577
|
WARNING_THRESHOLD,
|
|
8578
|
+
assertWithinBase,
|
|
8579
|
+
buildApiUrl,
|
|
8406
8580
|
buildInboundSecurityAdvisory,
|
|
8407
8581
|
classifyEmailRoute,
|
|
8408
8582
|
closeDatabase,
|
|
@@ -8421,12 +8595,17 @@ function parse(raw) {
|
|
|
8421
8595
|
parseEmail,
|
|
8422
8596
|
parseGoogleVoiceSms,
|
|
8423
8597
|
recordToolCall,
|
|
8598
|
+
redactObject,
|
|
8599
|
+
redactSecret,
|
|
8424
8600
|
resolveConfig,
|
|
8601
|
+
safeJoin,
|
|
8425
8602
|
sanitizeEmail,
|
|
8426
8603
|
saveConfig,
|
|
8427
8604
|
scanOutboundEmail,
|
|
8428
8605
|
scoreEmail,
|
|
8429
8606
|
setTelemetryVersion,
|
|
8430
8607
|
startRelayBridge,
|
|
8431
|
-
threadIdFor
|
|
8608
|
+
threadIdFor,
|
|
8609
|
+
tryJoin,
|
|
8610
|
+
validateApiUrl
|
|
8432
8611
|
});
|