@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 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((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
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((resolve) => {
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
- resolve(true);
1787
+ resolve2(true);
1778
1788
  });
1779
1789
  socket.on("error", () => {
1780
1790
  socket.destroy();
1781
- resolve(false);
1791
+ resolve2(false);
1782
1792
  });
1783
1793
  socket.on("timeout", () => {
1784
1794
  socket.destroy();
1785
- resolve(false);
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: join12 } = await import("path");
1858
- const configPath = join12(homedir11(), ".agenticmail", "stalwart.toml");
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: join12 } = require("path");
1873
- return join12(homedir11(), ".agenticmail", "stalwart.toml");
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: join12 } = require("path");
1879
- return join12(homedir11(), ".agenticmail");
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: join12 } = await import("path");
1992
+ const { join: join13 } = await import("path");
1983
1993
  const routeName = config.routeName ?? "gmail";
1984
- const tomlPath = join12(homedir11(), ".agenticmail", "stalwart.toml");
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
- return html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#0?39;/g, "'").replace(/&nbsp;/g, " ").replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)));
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(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#0?39;/g, "'").replace(/&nbsp;/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((resolve, reject) => {
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
- resolve();
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((resolve) => p.on("exit", () => resolve())),
5097
- new Promise((resolve) => setTimeout(resolve, 5e3))
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 isGoogleVoice = fromLower.includes("voice-noreply@google.com") || fromLower.includes("@txt.voice.google.com") || fromLower.includes("voice.google.com") || fromLower.includes("google.com/voice") || fromLower.includes("google") && fromLower.includes("voice");
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(/&nbsp;/gi, " ").replace(/&amp;/gi, "&").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&quot;/gi, '"').replace(/&#39;/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((resolve, reject) => {
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
- resolve();
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 import_node_path8 = require("path");
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 import_node_path5 = require("path");
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, import_node_path5.join)((0, import_node_os4.homedir)(), ".agenticmail", "bin", "cloudflared");
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 import_node_path6 = require("path");
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((resolve, reject) => {
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
- resolve({ exitCode: code ?? 1, fullOutput });
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((resolve, reject) => {
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) => resolve({ exitCode: code ?? 1, fullOutput }));
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, import_node_path6.join)((0, import_node_os5.homedir)(), ".docker", "cli-plugins");
7014
- const pluginPath = (0, import_node_path6.join)(pluginDir, "docker-compose");
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, import_node_path6.join)((0, import_node_os5.homedir)(), ".agenticmail", "tmp");
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, import_node_path6.join)(tmpDir, "install-docker.sh");
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, import_node_path6.join)(programFiles, "Docker", "Docker", "Docker Desktop.exe");
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, import_node_path6.join)(programFiles, "Docker", "Docker", "Docker Desktop.exe");
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, import_node_path6.join)((0, import_node_os5.homedir)(), ".agenticmail", "bin");
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, import_node_path6.join)(binDir, binName);
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, import_node_path6.join)(binDir, "cloudflared.tgz");
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 import_node_path7 = require("path");
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, import_node_path7.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
7547
+ return (0, import_node_path8.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
7380
7548
  } else {
7381
- return (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user", SYSTEMD_UNIT);
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, import_node_path7.join)("@agenticmail", "cli"),
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, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules")
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, import_node_path7.join)(prefix, "lib", "node_modules"));
7431
- baseDirs.push((0, import_node_path7.join)(prefix, "node_modules"));
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, import_node_path7.join)(base, "@agenticmail", "api", "dist", "index.js");
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, import_node_path7.join)(base, parent, "node_modules", "@agenticmail", "api", "dist", "index.js");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail");
7445
- const entryCache = (0, import_node_path7.join)(dataDir, "api-entry.path");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail");
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, import_node_path7.join)(dataDir, "api-entry.path"), entryPath);
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, import_node_path7.join)(apiEntry, "..", "..", "package.json");
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, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules", "@agenticmail", "cli", "package.json"),
7488
- (0, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules", "agenticmail", "package.json"),
7489
- (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "package-version.json")
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, import_node_path7.join)(prefix, "lib", "node_modules", "@agenticmail", "cli", "package.json"));
7494
- candidates.push((0, import_node_path7.join)(prefix, "lib", "node_modules", "agenticmail", "package.json"));
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin", "start-server.sh");
7514
- const scriptDir = (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "logs");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail")}</string>
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "config.json");
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, import_node_path7.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin", "start-server.sh");
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, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "api-entry.path");
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, import_node_path8.join)((0, import_node_os7.homedir)(), ".agenticmail", "docker-compose.yml");
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, import_node_path8.join)(cwd, "..")];
8104
+ const candidates = [cwd, (0, import_node_path9.join)(cwd, "..")];
7937
8105
  for (const dir of candidates) {
7938
- const p = (0, import_node_path8.join)(dir, "docker-compose.yml");
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, import_node_path8.join)((0, import_node_os7.homedir)(), ".agenticmail");
7950
- const configPath = (0, import_node_path8.join)(dataDir, "config.json");
7951
- const envPath = (0, import_node_path8.join)(dataDir, ".env");
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, import_node_path8.join)((0, import_node_os7.homedir)(), ".agenticmail");
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, import_node_path8.join)(dataDir, "docker-compose.yml");
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, import_node_path8.join)(dataDir, "stalwart.toml");
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, import_node_path8.join)((0, import_node_os7.homedir)(), ".agenticmail", "config.json");
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 m = addr.match(/<([^>]+)>/);
8125
- const raw = m ? m[1] : addr;
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 import_node_path9 = require("path");
8137
- var CACHE_DIR_DEFAULT = (0, import_node_path9.join)((0, import_node_os8.homedir)(), ".agenticmail", "thread-cache");
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, import_node_path9.join)(this.dir, `${threadId}.json`);
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, import_node_path9.join)(this.dir, f);
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 import_node_path10 = require("path");
8278
- var MEMORY_DIR_DEFAULT = (0, import_node_path10.join)((0, import_node_os9.homedir)(), ".agenticmail", "agent-memory");
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, import_node_path10.join)(this.dir, sanitizeId(agentId));
8458
+ return (0, import_node_path11.join)(this.dir, sanitizeId(agentId));
8290
8459
  }
8291
8460
  pathFor(agentId, threadId) {
8292
- return (0, import_node_path10.join)(this.dirFor(agentId), `${sanitizeId(threadId)}.md`);
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
  });