@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 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;
@@ -964,7 +974,13 @@ var MailReceiver = class {
964
974
  async fetchMessage(uid, mailbox = "INBOX") {
965
975
  const lock = await this.client.getMailboxLock(mailbox);
966
976
  try {
967
- const { content } = await this.client.download(String(uid), void 0, { uid: true });
977
+ const result = await this.client.download(String(uid), void 0, { uid: true });
978
+ const content = result?.content;
979
+ if (!content) {
980
+ const err = new Error(`Message UID ${uid} not found in mailbox "${mailbox}"`);
981
+ err.code = "MESSAGE_NOT_FOUND";
982
+ throw err;
983
+ }
968
984
  const chunks = [];
969
985
  for await (const chunk of content) {
970
986
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
@@ -1763,20 +1779,20 @@ var StalwartAdmin = class {
1763
1779
  }
1764
1780
  try {
1765
1781
  const net = await import("net");
1766
- return await new Promise((resolve) => {
1782
+ return await new Promise((resolve2) => {
1767
1783
  const smtpPort = parseInt(process.env.SMTP_PORT || "25", 10);
1768
1784
  const smtpHost = process.env.SMTP_HOST || "localhost";
1769
1785
  const socket = net.createConnection({ host: smtpHost, port: smtpPort, timeout: 3e3 }, () => {
1770
1786
  socket.destroy();
1771
- resolve(true);
1787
+ resolve2(true);
1772
1788
  });
1773
1789
  socket.on("error", () => {
1774
1790
  socket.destroy();
1775
- resolve(false);
1791
+ resolve2(false);
1776
1792
  });
1777
1793
  socket.on("timeout", () => {
1778
1794
  socket.destroy();
1779
- resolve(false);
1795
+ resolve2(false);
1780
1796
  });
1781
1797
  });
1782
1798
  } catch {
@@ -1848,8 +1864,8 @@ var StalwartAdmin = class {
1848
1864
  }
1849
1865
  const { readFileSync: readFileSync7, writeFileSync: writeFileSync8 } = await import("fs");
1850
1866
  const { homedir: homedir11 } = await import("os");
1851
- const { join: join12 } = await import("path");
1852
- const configPath = join12(homedir11(), ".agenticmail", "stalwart.toml");
1867
+ const { join: join13 } = await import("path");
1868
+ const configPath = join13(homedir11(), ".agenticmail", "stalwart.toml");
1853
1869
  try {
1854
1870
  let config = readFileSync7(configPath, "utf-8");
1855
1871
  config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
@@ -1863,14 +1879,14 @@ var StalwartAdmin = class {
1863
1879
  /** Path to the host-side stalwart.toml (mounted read-only into container) */
1864
1880
  get configPath() {
1865
1881
  const { homedir: homedir11 } = require("os");
1866
- const { join: join12 } = require("path");
1867
- return join12(homedir11(), ".agenticmail", "stalwart.toml");
1882
+ const { join: join13 } = require("path");
1883
+ return join13(homedir11(), ".agenticmail", "stalwart.toml");
1868
1884
  }
1869
1885
  /** Path to host-side DKIM key directory */
1870
1886
  get dkimDir() {
1871
1887
  const { homedir: homedir11 } = require("os");
1872
- const { join: join12 } = require("path");
1873
- return join12(homedir11(), ".agenticmail");
1888
+ const { join: join13 } = require("path");
1889
+ return join13(homedir11(), ".agenticmail");
1874
1890
  }
1875
1891
  /**
1876
1892
  * Create/reuse a DKIM signing key for a domain.
@@ -1973,9 +1989,9 @@ var StalwartAdmin = class {
1973
1989
  async configureOutboundRelay(config) {
1974
1990
  const { readFileSync: readFileSync7, writeFileSync: writeFileSync8 } = await import("fs");
1975
1991
  const { homedir: homedir11 } = await import("os");
1976
- const { join: join12 } = await import("path");
1992
+ const { join: join13 } = await import("path");
1977
1993
  const routeName = config.routeName ?? "gmail";
1978
- const tomlPath = join12(homedir11(), ".agenticmail", "stalwart.toml");
1994
+ const tomlPath = join13(homedir11(), ".agenticmail", "stalwart.toml");
1979
1995
  let toml = readFileSync7(tomlPath, "utf-8");
1980
1996
  toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
1981
1997
  toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
@@ -3083,7 +3099,8 @@ var OUTBOUND_TEXT_RULES = [
3083
3099
  var HIGH_RISK_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".p12", ".pfx", ".env", ".credentials", ".keystore", ".jks", ".p8"]);
3084
3100
  var MEDIUM_RISK_EXTENSIONS = /* @__PURE__ */ new Set([".db", ".sqlite", ".sqlite3", ".sql", ".csv", ".tsv", ".json", ".yml", ".yaml", ".conf", ".config", ".ini"]);
3085
3101
  function stripHtmlTags(html) {
3086
- 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)));
3087
3104
  }
3088
3105
  var TEXT_SCANNABLE_TYPES = /* @__PURE__ */ new Set([
3089
3106
  "text/plain",
@@ -4616,7 +4633,7 @@ var CloudflareClient = class {
4616
4633
  // --- Workers methods ---
4617
4634
  /** Deploy an Email Worker script (ES module format) */
4618
4635
  async deployEmailWorker(scriptName, scriptContent, envVars = {}) {
4619
- 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)}`;
4620
4637
  const bindings = Object.entries(envVars).map(([name, text2]) => ({
4621
4638
  type: "plain_text",
4622
4639
  name,
@@ -5034,7 +5051,7 @@ var TunnelManager = class {
5034
5051
  detached: false,
5035
5052
  env: { ...process.env, TUNNEL_TOKEN: tunnelToken }
5036
5053
  });
5037
- await new Promise((resolve, reject) => {
5054
+ await new Promise((resolve2, reject) => {
5038
5055
  let resolved = false;
5039
5056
  const timeout = setTimeout(() => {
5040
5057
  if (!resolved) {
@@ -5048,7 +5065,7 @@ var TunnelManager = class {
5048
5065
  resolved = true;
5049
5066
  clearTimeout(timeout);
5050
5067
  this.running = true;
5051
- resolve();
5068
+ resolve2();
5052
5069
  }
5053
5070
  };
5054
5071
  this.process.stderr?.on("data", onData);
@@ -5087,8 +5104,8 @@ var TunnelManager = class {
5087
5104
  this.process = null;
5088
5105
  p.kill("SIGTERM");
5089
5106
  await Promise.race([
5090
- new Promise((resolve) => p.on("exit", () => resolve())),
5091
- new Promise((resolve) => setTimeout(resolve, 5e3))
5107
+ new Promise((resolve2) => p.on("exit", () => resolve2())),
5108
+ new Promise((resolve2) => setTimeout(resolve2, 5e3))
5092
5109
  ]);
5093
5110
  this.running = false;
5094
5111
  }
@@ -5144,7 +5161,10 @@ function parseGoogleVoiceSms(emailBody, emailFrom) {
5144
5161
  if (!emailBody || typeof emailBody !== "string") return null;
5145
5162
  if (!emailFrom || typeof emailFrom !== "string") return null;
5146
5163
  const fromLower = emailFrom.toLowerCase();
5147
- 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"));
5148
5168
  if (!isGoogleVoice) return null;
5149
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();
5150
5170
  let from = "";
@@ -6175,6 +6195,15 @@ var GatewayManager = class {
6175
6195
  bcc: mail.bcc ? Array.isArray(mail.bcc) ? mail.bcc.join(", ") : mail.bcc : void 0,
6176
6196
  subject: mail.subject,
6177
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]
6178
6207
  html: mail.html || void 0,
6179
6208
  replyTo: mail.replyTo || from,
6180
6209
  inReplyTo: mail.inReplyTo || void 0,
@@ -6536,11 +6565,11 @@ var RelayBridge = class {
6536
6565
  this.options = options;
6537
6566
  }
6538
6567
  async start() {
6539
- return new Promise((resolve, reject) => {
6568
+ return new Promise((resolve2, reject) => {
6540
6569
  this.server = (0, import_node_http.createServer)((req, res) => this.handleRequest(req, res));
6541
6570
  this.server.listen(this.options.port, "127.0.0.1", () => {
6542
6571
  console.log(`[RelayBridge] Listening on 127.0.0.1:${this.options.port}`);
6543
- resolve();
6572
+ resolve2();
6544
6573
  });
6545
6574
  this.server.on("error", reject);
6546
6575
  });
@@ -6742,16 +6771,161 @@ try {
6742
6771
  } catch {
6743
6772
  }
6744
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
+
6745
6919
  // src/setup/index.ts
6746
6920
  var import_node_crypto3 = require("crypto");
6747
6921
  var import_node_fs7 = require("fs");
6748
- var import_node_path8 = require("path");
6922
+ var import_node_path9 = require("path");
6749
6923
  var import_node_os7 = require("os");
6750
6924
 
6751
6925
  // src/setup/deps.ts
6752
6926
  var import_node_child_process2 = require("child_process");
6753
6927
  var import_node_fs4 = require("fs");
6754
- var import_node_path5 = require("path");
6928
+ var import_node_path6 = require("path");
6755
6929
  var import_node_os4 = require("os");
6756
6930
  var DependencyChecker = class {
6757
6931
  async checkAll() {
@@ -6802,7 +6976,7 @@ var DependencyChecker = class {
6802
6976
  }
6803
6977
  }
6804
6978
  async checkCloudflared() {
6805
- 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");
6806
6980
  if ((0, import_node_fs4.existsSync)(binPath)) {
6807
6981
  let version;
6808
6982
  try {
@@ -6827,12 +7001,12 @@ var DependencyChecker = class {
6827
7001
  var import_node_child_process3 = require("child_process");
6828
7002
  var import_node_fs5 = require("fs");
6829
7003
  var import_promises2 = require("fs/promises");
6830
- var import_node_path6 = require("path");
7004
+ var import_node_path7 = require("path");
6831
7005
  var import_node_os5 = require("os");
6832
7006
  function runShellWithRollingOutput(cmd, opts = {}) {
6833
7007
  const maxLines = opts.maxLines ?? 20;
6834
7008
  const timeout = opts.timeout ?? 3e5;
6835
- return new Promise((resolve, reject) => {
7009
+ return new Promise((resolve2, reject) => {
6836
7010
  const child = (0, import_node_child_process3.spawn)("sh", ["-c", cmd], {
6837
7011
  stdio: ["ignore", "pipe", "pipe"],
6838
7012
  timeout
@@ -6874,7 +7048,7 @@ function runShellWithRollingOutput(cmd, opts = {}) {
6874
7048
  }
6875
7049
  process.stdout.write(`\x1B[${displayedCount}A`);
6876
7050
  }
6877
- resolve({ exitCode: code ?? 1, fullOutput });
7051
+ resolve2({ exitCode: code ?? 1, fullOutput });
6878
7052
  });
6879
7053
  child.on("error", (err) => {
6880
7054
  if (displayedCount > 0) {
@@ -6890,7 +7064,7 @@ function runShellWithRollingOutput(cmd, opts = {}) {
6890
7064
  }
6891
7065
  function runSilent(command, args, opts = {}) {
6892
7066
  const timeout = opts.timeout ?? 3e5;
6893
- return new Promise((resolve, reject) => {
7067
+ return new Promise((resolve2, reject) => {
6894
7068
  const child = (0, import_node_child_process3.spawn)(command, args, {
6895
7069
  stdio: ["ignore", "pipe", "pipe"],
6896
7070
  timeout
@@ -6902,7 +7076,7 @@ function runSilent(command, args, opts = {}) {
6902
7076
  child.stderr?.on("data", (d) => {
6903
7077
  fullOutput += d.toString();
6904
7078
  });
6905
- child.on("close", (code) => resolve({ exitCode: code ?? 1, fullOutput }));
7079
+ child.on("close", (code) => resolve2({ exitCode: code ?? 1, fullOutput }));
6906
7080
  child.on("error", reject);
6907
7081
  });
6908
7082
  }
@@ -7004,8 +7178,8 @@ var DependencyInstaller = class {
7004
7178
  try {
7005
7179
  const composeBin = (0, import_node_child_process3.execFileSync)("which", ["docker-compose"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
7006
7180
  if (!composeBin) return;
7007
- const pluginDir = (0, import_node_path6.join)((0, import_node_os5.homedir)(), ".docker", "cli-plugins");
7008
- 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");
7009
7183
  if ((0, import_node_fs5.existsSync)(pluginPath)) return;
7010
7184
  try {
7011
7185
  (0, import_node_fs5.mkdirSync)(pluginDir, { recursive: true });
@@ -7071,9 +7245,9 @@ var DependencyInstaller = class {
7071
7245
  return;
7072
7246
  }
7073
7247
  this.onProgress("__progress__:5:Installing Docker Engine...");
7074
- 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");
7075
7249
  await (0, import_promises2.mkdir)(tmpDir, { recursive: true });
7076
- const scriptPath = (0, import_node_path6.join)(tmpDir, "install-docker.sh");
7250
+ const scriptPath = (0, import_node_path7.join)(tmpDir, "install-docker.sh");
7077
7251
  const dlResult = await runShellWithRollingOutput(
7078
7252
  `curl -fsSL https://get.docker.com -o "${scriptPath}" && sudo sh "${scriptPath}"`,
7079
7253
  { timeout: 3e5 }
@@ -7141,7 +7315,7 @@ var DependencyInstaller = class {
7141
7315
  }
7142
7316
  try {
7143
7317
  const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
7144
- 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");
7145
7319
  if ((0, import_node_fs5.existsSync)(dockerExe)) {
7146
7320
  (0, import_node_child_process3.execSync)(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
7147
7321
  }
@@ -7192,7 +7366,7 @@ var DependencyInstaller = class {
7192
7366
  this.onProgress("__progress__:70:Docker Desktop installed. Starting...");
7193
7367
  try {
7194
7368
  const programFiles = process.env["ProgramFiles"] || "C:\\Program Files";
7195
- 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");
7196
7370
  if ((0, import_node_fs5.existsSync)(dockerExe)) {
7197
7371
  (0, import_node_child_process3.execSync)(`start "" "${dockerExe}"`, { timeout: 1e4, stdio: "ignore", shell: "cmd.exe" });
7198
7372
  }
@@ -7289,9 +7463,9 @@ var DependencyInstaller = class {
7289
7463
  */
7290
7464
  async installCloudflared() {
7291
7465
  const os = (0, import_node_os5.platform)();
7292
- 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");
7293
7467
  const binName = os === "win32" ? "cloudflared.exe" : "cloudflared";
7294
- const binPath = (0, import_node_path6.join)(binDir, binName);
7468
+ const binPath = (0, import_node_path7.join)(binDir, binName);
7295
7469
  if ((0, import_node_fs5.existsSync)(binPath)) {
7296
7470
  return binPath;
7297
7471
  }
@@ -7321,7 +7495,7 @@ var DependencyInstaller = class {
7321
7495
  }
7322
7496
  const buffer = Buffer.from(await response.arrayBuffer());
7323
7497
  if (os === "darwin") {
7324
- const tgzPath = (0, import_node_path6.join)(binDir, "cloudflared.tgz");
7498
+ const tgzPath = (0, import_node_path7.join)(binDir, "cloudflared.tgz");
7325
7499
  await (0, import_promises2.writeFile)(tgzPath, buffer);
7326
7500
  try {
7327
7501
  (0, import_node_child_process3.execFileSync)("tar", ["-xzf", tgzPath, "-C", binDir, "cloudflared"], { timeout: 15e3, stdio: "ignore" });
@@ -7357,7 +7531,7 @@ var DependencyInstaller = class {
7357
7531
  // src/setup/service.ts
7358
7532
  var import_node_child_process4 = require("child_process");
7359
7533
  var import_node_fs6 = require("fs");
7360
- var import_node_path7 = require("path");
7534
+ var import_node_path8 = require("path");
7361
7535
  var import_node_os6 = require("os");
7362
7536
  var import_node_module2 = require("module");
7363
7537
  var import_meta2 = {};
@@ -7370,9 +7544,9 @@ var ServiceManager = class {
7370
7544
  */
7371
7545
  getServicePath() {
7372
7546
  if (this.os === "darwin") {
7373
- 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`);
7374
7548
  } else {
7375
- 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);
7376
7550
  }
7377
7551
  }
7378
7552
  /**
@@ -7410,33 +7584,33 @@ var ServiceManager = class {
7410
7584
  } catch {
7411
7585
  }
7412
7586
  const parentPackages = [
7413
- (0, import_node_path7.join)("@agenticmail", "cli"),
7587
+ (0, import_node_path8.join)("@agenticmail", "cli"),
7414
7588
  // current scoped package
7415
7589
  "agenticmail"
7416
7590
  // legacy unscoped package
7417
7591
  ];
7418
7592
  const baseDirs = [
7419
7593
  // user-local install
7420
- (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")
7421
7595
  ];
7422
7596
  try {
7423
7597
  const prefix = (0, import_node_child_process4.execSync)("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
7424
- baseDirs.push((0, import_node_path7.join)(prefix, "lib", "node_modules"));
7425
- 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"));
7426
7600
  } catch {
7427
7601
  }
7428
7602
  baseDirs.push("/opt/homebrew/lib/node_modules");
7429
7603
  baseDirs.push("/usr/local/lib/node_modules");
7430
7604
  for (const base of baseDirs) {
7431
- 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");
7432
7606
  if ((0, import_node_fs6.existsSync)(sibling)) return sibling;
7433
7607
  for (const parent of parentPackages) {
7434
- 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");
7435
7609
  if ((0, import_node_fs6.existsSync)(nested)) return nested;
7436
7610
  }
7437
7611
  }
7438
- const dataDir = (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail");
7439
- 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");
7440
7614
  if ((0, import_node_fs6.existsSync)(entryCache)) {
7441
7615
  const cached = (0, import_node_fs6.readFileSync)(entryCache, "utf-8").trim();
7442
7616
  if (cached && (0, import_node_fs6.existsSync)(cached)) return cached;
@@ -7447,9 +7621,9 @@ var ServiceManager = class {
7447
7621
  * Cache the API entry path so the service can find it later.
7448
7622
  */
7449
7623
  cacheApiEntryPath(entryPath) {
7450
- 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");
7451
7625
  if (!(0, import_node_fs6.existsSync)(dataDir)) (0, import_node_fs6.mkdirSync)(dataDir, { recursive: true });
7452
- (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);
7453
7627
  }
7454
7628
  /**
7455
7629
  * Get the current package version.
@@ -7470,7 +7644,7 @@ var ServiceManager = class {
7470
7644
  }
7471
7645
  try {
7472
7646
  const apiEntry = this.getApiEntryPath();
7473
- const apiPkg = (0, import_node_path7.join)(apiEntry, "..", "..", "package.json");
7647
+ const apiPkg = (0, import_node_path8.join)(apiEntry, "..", "..", "package.json");
7474
7648
  if ((0, import_node_fs6.existsSync)(apiPkg)) {
7475
7649
  const pkg = JSON.parse((0, import_node_fs6.readFileSync)(apiPkg, "utf-8"));
7476
7650
  if (pkg.version) return pkg.version;
@@ -7478,14 +7652,14 @@ var ServiceManager = class {
7478
7652
  } catch {
7479
7653
  }
7480
7654
  const candidates = [
7481
- (0, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules", "@agenticmail", "cli", "package.json"),
7482
- (0, import_node_path7.join)((0, import_node_os6.homedir)(), "node_modules", "agenticmail", "package.json"),
7483
- (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")
7484
7658
  ];
7485
7659
  try {
7486
7660
  const prefix = (0, import_node_child_process4.execSync)("npm prefix -g", { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
7487
- candidates.push((0, import_node_path7.join)(prefix, "lib", "node_modules", "@agenticmail", "cli", "package.json"));
7488
- 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"));
7489
7663
  } catch {
7490
7664
  }
7491
7665
  for (const p of candidates) {
@@ -7504,8 +7678,8 @@ var ServiceManager = class {
7504
7678
  * This ensures AgenticMail doesn't fail on boot when Docker is still loading.
7505
7679
  */
7506
7680
  generateStartScript(nodePath, apiEntry) {
7507
- const scriptPath = (0, import_node_path7.join)((0, import_node_os6.homedir)(), ".agenticmail", "bin", "start-server.sh");
7508
- 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");
7509
7683
  if (!(0, import_node_fs6.existsSync)(scriptDir)) (0, import_node_fs6.mkdirSync)(scriptDir, { recursive: true });
7510
7684
  const script = [
7511
7685
  "#!/bin/bash",
@@ -7571,7 +7745,7 @@ var ServiceManager = class {
7571
7745
  */
7572
7746
  generatePlist(nodePath, apiEntry, configPath) {
7573
7747
  const config = JSON.parse((0, import_node_fs6.readFileSync)(configPath, "utf-8"));
7574
- 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");
7575
7749
  if (!(0, import_node_fs6.existsSync)(logDir)) (0, import_node_fs6.mkdirSync)(logDir, { recursive: true });
7576
7750
  const version = this.getVersion();
7577
7751
  const startScript = this.generateStartScript(nodePath, apiEntry);
@@ -7595,7 +7769,7 @@ var ServiceManager = class {
7595
7769
  <key>HOME</key>
7596
7770
  <string>${(0, import_node_os6.homedir)()}</string>
7597
7771
  <key>AGENTICMAIL_DATA_DIR</key>
7598
- <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>
7599
7773
  <key>PATH</key>
7600
7774
  <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
7601
7775
  <key>AGENTICMAIL_SERVICE_VERSION</key>
@@ -7649,7 +7823,7 @@ var ServiceManager = class {
7649
7823
  */
7650
7824
  generateSystemdUnit(nodePath, apiEntry, configPath) {
7651
7825
  const config = JSON.parse((0, import_node_fs6.readFileSync)(configPath, "utf-8"));
7652
- 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");
7653
7827
  const version = this.getVersion();
7654
7828
  const startScript = this.generateStartScript(nodePath, apiEntry);
7655
7829
  return `[Unit]
@@ -7679,7 +7853,7 @@ WantedBy=default.target
7679
7853
  * Install the auto-start service.
7680
7854
  */
7681
7855
  install() {
7682
- 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");
7683
7857
  if (!(0, import_node_fs6.existsSync)(configPath)) {
7684
7858
  return { installed: false, message: "Config not found. Run agenticmail setup first." };
7685
7859
  }
@@ -7692,7 +7866,7 @@ WantedBy=default.target
7692
7866
  }
7693
7867
  const servicePath = this.getServicePath();
7694
7868
  if (this.os === "darwin") {
7695
- 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");
7696
7870
  if (!(0, import_node_fs6.existsSync)(dir)) (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
7697
7871
  if ((0, import_node_fs6.existsSync)(servicePath)) {
7698
7872
  try {
@@ -7710,7 +7884,7 @@ WantedBy=default.target
7710
7884
  }
7711
7885
  return { installed: true, message: `Service installed at ${servicePath}` };
7712
7886
  } else if (this.os === "linux") {
7713
- 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");
7714
7888
  if (!(0, import_node_fs6.existsSync)(dir)) (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
7715
7889
  const unit = this.generateSystemdUnit(nodePath, apiEntry, configPath);
7716
7890
  (0, import_node_fs6.writeFileSync)(servicePath, unit);
@@ -7836,7 +8010,7 @@ WantedBy=default.target
7836
8010
  } catch {
7837
8011
  return { reason: "Service file unreadable" };
7838
8012
  }
7839
- 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");
7840
8014
  if (serviceContent.includes(startScript)) {
7841
8015
  if (!(0, import_node_fs6.existsSync)(startScript)) {
7842
8016
  return { reason: "start-server.sh is missing" };
@@ -7869,7 +8043,7 @@ WantedBy=default.target
7869
8043
  return { reason: `Service version drift (current CLI is v${currentVersion})` };
7870
8044
  }
7871
8045
  }
7872
- 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");
7873
8047
  if ((0, import_node_fs6.existsSync)(entryCache)) {
7874
8048
  try {
7875
8049
  const cached = (0, import_node_fs6.readFileSync)(entryCache, "utf-8").trim();
@@ -7924,12 +8098,12 @@ var SetupManager = class {
7924
8098
  * falls back to monorepo location.
7925
8099
  */
7926
8100
  getComposePath() {
7927
- 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");
7928
8102
  if ((0, import_node_fs7.existsSync)(standalonePath)) return standalonePath;
7929
8103
  const cwd = process.cwd();
7930
- const candidates = [cwd, (0, import_node_path8.join)(cwd, "..")];
8104
+ const candidates = [cwd, (0, import_node_path9.join)(cwd, "..")];
7931
8105
  for (const dir of candidates) {
7932
- const p = (0, import_node_path8.join)(dir, "docker-compose.yml");
8106
+ const p = (0, import_node_path9.join)(dir, "docker-compose.yml");
7933
8107
  if ((0, import_node_fs7.existsSync)(p)) return p;
7934
8108
  }
7935
8109
  return standalonePath;
@@ -7940,9 +8114,9 @@ var SetupManager = class {
7940
8114
  * Always regenerates Docker files to keep passwords in sync.
7941
8115
  */
7942
8116
  initConfig() {
7943
- const dataDir = (0, import_node_path8.join)((0, import_node_os7.homedir)(), ".agenticmail");
7944
- const configPath = (0, import_node_path8.join)(dataDir, "config.json");
7945
- 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");
7946
8120
  if ((0, import_node_fs7.existsSync)(configPath)) {
7947
8121
  try {
7948
8122
  const existing = JSON.parse((0, import_node_fs7.readFileSync)(configPath, "utf-8"));
@@ -7994,12 +8168,12 @@ IMAP_PORT=143
7994
8168
  * with the correct admin password from config.
7995
8169
  */
7996
8170
  generateDockerFiles(config) {
7997
- 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");
7998
8172
  if (!(0, import_node_fs7.existsSync)(dataDir)) {
7999
8173
  (0, import_node_fs7.mkdirSync)(dataDir, { recursive: true });
8000
8174
  }
8001
8175
  const password = config.stalwart?.adminPassword || "changeme";
8002
- const composePath = (0, import_node_path8.join)(dataDir, "docker-compose.yml");
8176
+ const composePath = (0, import_node_path9.join)(dataDir, "docker-compose.yml");
8003
8177
  (0, import_node_fs7.writeFileSync)(composePath, `services:
8004
8178
  stalwart:
8005
8179
  # Pinned to v0.15.5 \u2014 Stalwart 0.16+ moved its config to JSON
@@ -8030,7 +8204,7 @@ volumes:
8030
8204
  stalwart-data:
8031
8205
  `);
8032
8206
  (0, import_node_fs7.chmodSync)(composePath, 384);
8033
- const tomlPath = (0, import_node_path8.join)(dataDir, "stalwart.toml");
8207
+ const tomlPath = (0, import_node_path9.join)(dataDir, "stalwart.toml");
8034
8208
  (0, import_node_fs7.writeFileSync)(tomlPath, `# Stalwart Mail Server \u2014 AgenticMail Configuration
8035
8209
 
8036
8210
  [server]
@@ -8087,7 +8261,7 @@ secret = "${password}"
8087
8261
  * Check if config has already been initialized.
8088
8262
  */
8089
8263
  isInitialized() {
8090
- 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");
8091
8265
  return (0, import_node_fs7.existsSync)(configPath);
8092
8266
  }
8093
8267
  };
@@ -8095,7 +8269,7 @@ secret = "${password}"
8095
8269
  // src/threading/thread-id.ts
8096
8270
  var import_node_crypto4 = require("crypto");
8097
8271
  function stripReplyPrefixes(subject) {
8098
- let s = subject;
8272
+ let s = subject.length > 1e3 ? subject.slice(0, 1e3) : subject;
8099
8273
  for (; ; ) {
8100
8274
  const next = s.replace(/^\s*(?:re|fwd?|fw)\s*(?:\[\d+\])?\s*:\s*/i, "");
8101
8275
  if (next === s) break;
@@ -8115,8 +8289,9 @@ function normalizeSubject(subject) {
8115
8289
  }
8116
8290
  function normalizeAddress(addr) {
8117
8291
  if (!addr) return "(unknown)";
8118
- const m = addr.match(/<([^>]+)>/);
8119
- 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;
8120
8295
  return raw.trim().toLowerCase();
8121
8296
  }
8122
8297
  function threadIdFor(input) {
@@ -8127,8 +8302,8 @@ function threadIdFor(input) {
8127
8302
  // src/threading/thread-cache.ts
8128
8303
  var import_node_fs8 = require("fs");
8129
8304
  var import_node_os8 = require("os");
8130
- var import_node_path9 = require("path");
8131
- 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");
8132
8307
  var DEFAULT_K_MESSAGES = 10;
8133
8308
  var DEFAULT_LRU_CAP = 5e3;
8134
8309
  var PREVIEW_MAX_CHARS = 240;
@@ -8146,7 +8321,7 @@ var ThreadCache = class {
8146
8321
  }
8147
8322
  }
8148
8323
  pathFor(threadId) {
8149
- return (0, import_node_path9.join)(this.dir, `${threadId}.json`);
8324
+ return (0, import_node_path10.join)(this.dir, `${threadId}.json`);
8150
8325
  }
8151
8326
  read(threadId) {
8152
8327
  const p = this.pathFor(threadId);
@@ -8236,7 +8411,7 @@ var ThreadCache = class {
8236
8411
  }
8237
8412
  if (files.length <= this.lruCap) return;
8238
8413
  const stats = files.map((f) => {
8239
- const p = (0, import_node_path9.join)(this.dir, f);
8414
+ const p = (0, import_node_path10.join)(this.dir, f);
8240
8415
  try {
8241
8416
  return { p, mtime: (0, import_node_fs8.statSync)(p).mtimeMs };
8242
8417
  } catch {
@@ -8268,8 +8443,8 @@ function dedupAndCap(messages, k) {
8268
8443
  // src/threading/agent-memory.ts
8269
8444
  var import_node_fs9 = require("fs");
8270
8445
  var import_node_os9 = require("os");
8271
- var import_node_path10 = require("path");
8272
- 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");
8273
8448
  var AgentMemoryStore = class {
8274
8449
  dir;
8275
8450
  constructor(opts = {}) {
@@ -8280,10 +8455,10 @@ var AgentMemoryStore = class {
8280
8455
  }
8281
8456
  }
8282
8457
  dirFor(agentId) {
8283
- return (0, import_node_path10.join)(this.dir, sanitizeId(agentId));
8458
+ return (0, import_node_path11.join)(this.dir, sanitizeId(agentId));
8284
8459
  }
8285
8460
  pathFor(agentId, threadId) {
8286
- 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`);
8287
8462
  }
8288
8463
  read(agentId, threadId) {
8289
8464
  const p = this.pathFor(agentId, threadId);
@@ -8385,6 +8560,8 @@ function parse(raw) {
8385
8560
  InboxWatcher,
8386
8561
  MailReceiver,
8387
8562
  MailSender,
8563
+ PathTraversalError,
8564
+ REDACTED,
8388
8565
  RELAY_PRESETS,
8389
8566
  RelayBridge,
8390
8567
  RelayGateway,
@@ -8396,7 +8573,10 @@ function parse(raw) {
8396
8573
  StalwartAdmin,
8397
8574
  ThreadCache,
8398
8575
  TunnelManager,
8576
+ UnsafeApiUrlError,
8399
8577
  WARNING_THRESHOLD,
8578
+ assertWithinBase,
8579
+ buildApiUrl,
8400
8580
  buildInboundSecurityAdvisory,
8401
8581
  classifyEmailRoute,
8402
8582
  closeDatabase,
@@ -8415,12 +8595,17 @@ function parse(raw) {
8415
8595
  parseEmail,
8416
8596
  parseGoogleVoiceSms,
8417
8597
  recordToolCall,
8598
+ redactObject,
8599
+ redactSecret,
8418
8600
  resolveConfig,
8601
+ safeJoin,
8419
8602
  sanitizeEmail,
8420
8603
  saveConfig,
8421
8604
  scanOutboundEmail,
8422
8605
  scoreEmail,
8423
8606
  setTelemetryVersion,
8424
8607
  startRelayBridge,
8425
- threadIdFor
8608
+ threadIdFor,
8609
+ tryJoin,
8610
+ validateApiUrl
8426
8611
  });