@essentialai/cogent-bridge 3.14.0 → 3.15.0

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/cloud/mail-credential-store.d.ts +46 -0
  3. package/dist/cloud/mail-credential-store.d.ts.map +1 -0
  4. package/dist/cloud/mail-credential-store.js +80 -0
  5. package/dist/cloud/mail-credential-store.js.map +1 -0
  6. package/dist/config.d.ts +6 -6
  7. package/dist/index.js +6 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/mail/mail-fetcher.d.ts +112 -0
  10. package/dist/mail/mail-fetcher.d.ts.map +1 -0
  11. package/dist/mail/mail-fetcher.js +186 -0
  12. package/dist/mail/mail-fetcher.js.map +1 -0
  13. package/dist/mail/mail-sender.d.ts +64 -0
  14. package/dist/mail/mail-sender.d.ts.map +1 -0
  15. package/dist/mail/mail-sender.js +68 -0
  16. package/dist/mail/mail-sender.js.map +1 -0
  17. package/dist/mail/validate.d.ts +4 -0
  18. package/dist/mail/validate.d.ts.map +1 -0
  19. package/dist/mail/validate.js +16 -0
  20. package/dist/mail/validate.js.map +1 -0
  21. package/dist/tools/fetch-mail.d.ts +16 -0
  22. package/dist/tools/fetch-mail.d.ts.map +1 -0
  23. package/dist/tools/fetch-mail.js +55 -0
  24. package/dist/tools/fetch-mail.js.map +1 -0
  25. package/dist/tools/register-peer.d.ts.map +1 -1
  26. package/dist/tools/register-peer.js +13 -0
  27. package/dist/tools/register-peer.js.map +1 -1
  28. package/dist/tools/send-mail.d.ts +16 -0
  29. package/dist/tools/send-mail.d.ts.map +1 -0
  30. package/dist/tools/send-mail.js +49 -0
  31. package/dist/tools/send-mail.js.map +1 -0
  32. package/dist/tools/setup-mail.d.ts +10 -0
  33. package/dist/tools/setup-mail.d.ts.map +1 -0
  34. package/dist/tools/setup-mail.js +47 -0
  35. package/dist/tools/setup-mail.js.map +1 -0
  36. package/dist/types.d.ts +11 -0
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/wizard/index.d.ts.map +1 -1
  39. package/dist/wizard/index.js +6 -0
  40. package/dist/wizard/index.js.map +1 -1
  41. package/dist/wizard/scaffold-real.d.ts +3 -0
  42. package/dist/wizard/scaffold-real.d.ts.map +1 -1
  43. package/dist/wizard/scaffold-real.js +6 -5
  44. package/dist/wizard/scaffold-real.js.map +1 -1
  45. package/dist/wizard/templates.d.ts +4 -2
  46. package/dist/wizard/templates.d.ts.map +1 -1
  47. package/dist/wizard/templates.js +21 -10
  48. package/dist/wizard/templates.js.map +1 -1
  49. package/package.json +3 -1
  50. package/server.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.15.0 — 2026-08-08
4
+
5
+ ### Added — Cogent Mail: per-agent mailboxes + auto-provision (M2)
6
+ - **New agent tools**: `cogent_setup_mail` (store the mailbox address+password locally, 0600),
7
+ `cogent_send_mail` (SMTP submission with attachments read from local paths), and
8
+ `cogent_fetch_mail` (on-demand IMAP list/fetch; saves attachments by basename). Every mailbox
9
+ is `[agent]-[channel]@mail.cogent.tools` on the standalone Stalwart box.
10
+ - **Zero-touch provisioning for Team agents**: on a cloud Team `cogent_register_peer`, the relay
11
+ mints (or idempotently resolves) the peer's mailbox via the control plane and returns
12
+ `{address, password}` in the register response; the bridge saves it to its per-cwd 0600 store —
13
+ no manual `cogent_setup_mail` needed. `PeerInfo.mailbox` (response-only; password never stored
14
+ server-side).
15
+ - **A2A card autofill**: each peer's Agent Card advertises its mailbox address via a
16
+ `capabilities.extensions[]` entry (address only; the password never touches the card).
17
+ - Input hardening: `cogent_send_mail`/`cogent_setup_mail` validate the address shape before the
18
+ SMTP/credential sink. `nodemailer`/`imapflow` are lazy-imported (off the cold-start path).
19
+
20
+ ## 3.14.1 — 2026-08-07
21
+
22
+ ### Added — `cogent init` asks Local vs Cloud (writes the config; no hand-edit)
23
+ - The interactive setup wizard (`cogent init`, Real mode) now asks **"How should these agents connect?"**
24
+ with two choices:
25
+ - **Cloud** (default, recommended) — collaborate with remote agents over `cogent.tools`. Relies on the
26
+ 3.14.0 zero-config default, so the written `.mcp.json` adds nothing extra.
27
+ - **Local** — offline, this machine only (self-hosted / local-LLM / air-gapped). Writes `COGENT_LOCAL=1`
28
+ into each project's `.mcp.json` so the bridge uses on-machine file state and never contacts a relay.
29
+ - The wizard **writes the chosen mode into the config** — the user never hand-edits a settings file. Cloud
30
+ is the default at every layer (default parameter `mode="cloud"`), so the demo scaffolder path is unchanged.
31
+ - No runtime/bridge behavior change (the bridge already honors `COGENT_LOCAL` since 3.14.0); this is an
32
+ additive wizard-UX release. Wizard unit tests cover both modes; full suite green.
33
+
3
34
  ## 3.14.0 — 2026-08-06
4
35
 
5
36
  ### Changed — Cloud is now the zero-config default (Local vs Cloud mode)
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Agent-owned local mailbox credentials (Cogent Mail M2). The mailbox password is a
3
+ * SECRET — the control plane hands it to the bridge ONCE (on provisioning/rotation)
4
+ * and never stores it, so the ONLY durable copy lives here, in an owner-only file.
5
+ * `cogent_send_mail` / `cogent_fetch_mail` read it; `cogent_rotate_mail_creds` updates it.
6
+ *
7
+ * Mirrors {@link ./credential-store} deliberately: a per-cwd file so project A's mailbox
8
+ * can't bleed into project B (the same isolation the cloud-credential store enforces).
9
+ */
10
+ export interface PersistedMailCredentials {
11
+ /** Full mailbox address `[peer]-[channel]@mail.cogent.tools`. */
12
+ address: string;
13
+ /** Mailbox password (SECRET) — used for SMTP submission + IMAP fetch. */
14
+ password: string;
15
+ imapHost: string;
16
+ imapPort: number;
17
+ smtpHost: string;
18
+ smtpPort: number;
19
+ savedAt: string;
20
+ }
21
+ /** The Cogent Mail box hostname — default IMAP/SMTP host for a mailbox (M2). */
22
+ export declare const MAIL_DEFAULT_HOST = "mail.cogent.tools";
23
+ /**
24
+ * Resolve the mailbox-credential path with the override hierarchy:
25
+ * 1. explicit `credentialPath` arg (tests, advanced users)
26
+ * 2. process.env.COGENT_MAIL_CREDENTIALS_FILE (operators with custom paths)
27
+ * 3. defaultMailCredentialPath(process.cwd()) (per-cwd, the default)
28
+ */
29
+ export declare function resolveMailCredentialPath(credentialPath?: string): string;
30
+ /** Load persisted mailbox credentials. Returns null on any error (absent / corrupt). */
31
+ export declare function loadMailCredentials(credentialPath?: string): Promise<PersistedMailCredentials | null>;
32
+ /** Save (upsert) mailbox credentials as 0600 JSON; creates the owner-only parent dir. */
33
+ export declare function saveMailCredentials(creds: PersistedMailCredentials, credentialPath?: string): Promise<void>;
34
+ /**
35
+ * Persist an auto-provisioned mailbox (Cogent Mail M2.7) with default hosts (IMAP 993 / SMTP 465
36
+ * on {@link MAIL_DEFAULT_HOST}). Returns true if it saved, false if there was nothing to save
37
+ * (no address, or no one-time password — e.g. a re-register that didn't re-issue the password).
38
+ * The caller uses this best-effort: a save failure must not break peer registration.
39
+ */
40
+ export declare function persistProvisionedMailbox(mailbox: {
41
+ address?: string;
42
+ password?: string;
43
+ } | undefined, credentialPath?: string): Promise<boolean>;
44
+ /** Delete the mailbox-credential file. Idempotent — a missing file is not an error. */
45
+ export declare function clearMailCredentials(credentialPath?: string): Promise<void>;
46
+ //# sourceMappingURL=mail-credential-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-credential-store.d.ts","sourceRoot":"","sources":["../../src/cloud/mail-credential-store.ts"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AAYrD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAKzE;AAED,wFAAwF;AACxF,wBAAsB,mBAAmB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAO3G;AAED,yFAAyF;AACzF,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjH;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAC5D,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,OAAO,CAAC,CAelB;AAED,uFAAuF;AACvF,wBAAsB,oBAAoB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjF"}
@@ -0,0 +1,80 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ /** The Cogent Mail box hostname — default IMAP/SMTP host for a mailbox (M2). */
6
+ export const MAIL_DEFAULT_HOST = "mail.cogent.tools";
7
+ /**
8
+ * Per-cwd default location:
9
+ * ~/.cogent/mail-credentials/<sha256(absoluteCwd)[..16]>.json
10
+ * Each working directory (= one agent identity = one mailbox) gets its own file.
11
+ */
12
+ function defaultMailCredentialPath(cwd = process.cwd()) {
13
+ const hash = crypto.createHash("sha256").update(path.resolve(cwd)).digest("hex").slice(0, 16);
14
+ return path.join(os.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
15
+ }
16
+ /**
17
+ * Resolve the mailbox-credential path with the override hierarchy:
18
+ * 1. explicit `credentialPath` arg (tests, advanced users)
19
+ * 2. process.env.COGENT_MAIL_CREDENTIALS_FILE (operators with custom paths)
20
+ * 3. defaultMailCredentialPath(process.cwd()) (per-cwd, the default)
21
+ */
22
+ export function resolveMailCredentialPath(credentialPath) {
23
+ if (credentialPath)
24
+ return credentialPath;
25
+ const envOverride = process.env.COGENT_MAIL_CREDENTIALS_FILE;
26
+ if (envOverride)
27
+ return envOverride;
28
+ return defaultMailCredentialPath();
29
+ }
30
+ /** Load persisted mailbox credentials. Returns null on any error (absent / corrupt). */
31
+ export async function loadMailCredentials(credentialPath) {
32
+ const filePath = resolveMailCredentialPath(credentialPath);
33
+ try {
34
+ return JSON.parse(await fs.readFile(filePath, "utf-8"));
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ /** Save (upsert) mailbox credentials as 0600 JSON; creates the owner-only parent dir. */
41
+ export async function saveMailCredentials(creds, credentialPath) {
42
+ const filePath = resolveMailCredentialPath(credentialPath);
43
+ // The password is a secret: owner-only dir + file. `mode` on mkdir/writeFile only
44
+ // applies on creation, so chmod afterward to also tighten a pre-existing file.
45
+ await fs.mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 });
46
+ await fs.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
47
+ await fs.chmod(filePath, 0o600);
48
+ }
49
+ /**
50
+ * Persist an auto-provisioned mailbox (Cogent Mail M2.7) with default hosts (IMAP 993 / SMTP 465
51
+ * on {@link MAIL_DEFAULT_HOST}). Returns true if it saved, false if there was nothing to save
52
+ * (no address, or no one-time password — e.g. a re-register that didn't re-issue the password).
53
+ * The caller uses this best-effort: a save failure must not break peer registration.
54
+ */
55
+ export async function persistProvisionedMailbox(mailbox, credentialPath) {
56
+ if (!mailbox?.address || !mailbox.password)
57
+ return false;
58
+ await saveMailCredentials({
59
+ address: mailbox.address,
60
+ password: mailbox.password,
61
+ imapHost: MAIL_DEFAULT_HOST,
62
+ imapPort: 993,
63
+ smtpHost: MAIL_DEFAULT_HOST,
64
+ smtpPort: 465,
65
+ savedAt: new Date().toISOString(),
66
+ }, credentialPath);
67
+ return true;
68
+ }
69
+ /** Delete the mailbox-credential file. Idempotent — a missing file is not an error. */
70
+ export async function clearMailCredentials(credentialPath) {
71
+ const filePath = resolveMailCredentialPath(credentialPath);
72
+ try {
73
+ await fs.unlink(filePath);
74
+ }
75
+ catch (err) {
76
+ if (err.code !== "ENOENT")
77
+ throw err;
78
+ }
79
+ }
80
+ //# sourceMappingURL=mail-credential-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-credential-store.js","sourceRoot":"","sources":["../../src/cloud/mail-credential-store.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -29,13 +29,13 @@ export declare const configSchema: z.ZodObject<{
29
29
  COGENT_CHECK_ON_STOP: z.ZodEffects<z.ZodOptional<z.ZodString>, boolean, string | undefined>;
30
30
  COGENT_CHECK_ON_STOP_SCOPE: z.ZodDefault<z.ZodString>;
31
31
  }, "strip", z.ZodTypeAny, {
32
+ COGENT_LOG_LEVEL: "info" | "debug" | "warn" | "error";
33
+ COGENT_TIMEOUT_MS: number;
32
34
  COGENT_STATE_PATH: string;
33
35
  COGENT_TEAM_ENDPOINT: string;
34
36
  COGENT_POLL_INTERVAL_MS: number;
35
- COGENT_TIMEOUT_MS: number;
36
37
  COGENT_FASTPATH_MS: number;
37
38
  COGENT_CHAR_LIMIT: number;
38
- COGENT_LOG_LEVEL: "info" | "debug" | "warn" | "error";
39
39
  COGENT_CLAUDE_PATH: string;
40
40
  COGENT_STALE_TIMEOUT_MS: number;
41
41
  COGENT_HEARTBEAT_INTERVAL_MS: number;
@@ -51,22 +51,22 @@ export declare const configSchema: z.ZodObject<{
51
51
  COGENT_BROADCAST_MANUAL: boolean;
52
52
  COGENT_CHECK_ON_STOP: boolean;
53
53
  COGENT_CHECK_ON_STOP_SCOPE: string;
54
- COGENT_ENDPOINT?: string | undefined;
55
54
  COGENT_LOCAL?: string | undefined;
55
+ COGENT_ENDPOINT?: string | undefined;
56
56
  COGENT_SESSION_ID?: string | undefined;
57
57
  COGENT_SECRET?: string | undefined;
58
58
  }, {
59
+ COGENT_LOG_LEVEL?: "info" | "debug" | "warn" | "error" | undefined;
60
+ COGENT_TIMEOUT_MS?: number | undefined;
61
+ COGENT_LOCAL?: string | undefined;
59
62
  COGENT_STATE_PATH?: string | undefined;
60
63
  COGENT_ENDPOINT?: string | undefined;
61
- COGENT_LOCAL?: string | undefined;
62
64
  COGENT_TEAM_ENDPOINT?: string | undefined;
63
65
  COGENT_SESSION_ID?: string | undefined;
64
66
  COGENT_SECRET?: string | undefined;
65
67
  COGENT_POLL_INTERVAL_MS?: number | undefined;
66
- COGENT_TIMEOUT_MS?: number | undefined;
67
68
  COGENT_FASTPATH_MS?: number | undefined;
68
69
  COGENT_CHAR_LIMIT?: number | undefined;
69
- COGENT_LOG_LEVEL?: "info" | "debug" | "warn" | "error" | undefined;
70
70
  COGENT_CLAUDE_PATH?: string | undefined;
71
71
  COGENT_STALE_TIMEOUT_MS?: number | undefined;
72
72
  COGENT_HEARTBEAT_INTERVAL_MS?: number | undefined;
package/dist/index.js CHANGED
@@ -12,6 +12,9 @@ import { registerDeregisterPeerTool } from "./tools/deregister-peer.js";
12
12
  import { registerHealthCheckTool } from "./tools/health-check.js";
13
13
  import { registerCreateSessionTool } from "./tools/create-session.js";
14
14
  import { registerJoinSessionTool } from "./tools/join-session.js";
15
+ import { registerSetupMailTool } from "./tools/setup-mail.js";
16
+ import { registerSendMailTool } from "./tools/send-mail.js";
17
+ import { registerFetchMailTool } from "./tools/fetch-mail.js";
15
18
  import { heartbeat } from "./services/heartbeat.js";
16
19
  // ---------------------------------------------------------------------------
17
20
  // Global error handlers -- registered FIRST before anything else
@@ -70,6 +73,9 @@ async function main() {
70
73
  registerHealthCheckTool(server);
71
74
  registerCreateSessionTool(server);
72
75
  registerJoinSessionTool(server);
76
+ registerSetupMailTool(server);
77
+ registerSendMailTool(server);
78
+ registerFetchMailTool(server);
73
79
  // Register MCP inbox resource if cloud mode is active
74
80
  if (cloudInbox) {
75
81
  server.registerResource("cogent_inbox", "cogent://inbox", {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,8EAA8E;AAC9E,iEAAiE;AACjE,8EAA8E;AAE9E,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;IACtC,8DAA8D;IAC9D,IAAK,GAA6B,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACpD,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,uBAAuB,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACzE,mDAAmD;AACrD,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;IAC1C,MAAM,GAAG,GAAG,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAE9E,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC/C,SAAS,CAAC,IAAI,EAAE,CAAC;IACjB,SAAS,CAAC,IAAI,EAAE,CAAC;IACjB,IAAI,aAAa,EAAE,CAAC;QAClB,aAAa,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IACD,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAC9C,SAAS,CAAC,IAAI,EAAE,CAAC;IACjB,SAAS,CAAC,IAAI,EAAE,CAAC;IACjB,IAAI,aAAa,EAAE,CAAC;QAClB,aAAa,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IACD,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,KAAK,UAAU,IAAI;IACjB,oDAAoD;IACpD,sEAAsE;IACtE,MAAM,UAAU,EAAE,CAAC;IAEnB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IAE7E,oEAAoE;IACpE,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAEhC,sDAAsD;IACtD,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,CAAC,gBAAgB,CACrB,cAAc,EACd,gBAAgB,EAChB;YACE,WAAW,EAAE,iHAAiH;YAC9H,QAAQ,EAAE,kBAAkB;SAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACd,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,QAAQ,EAAE,UAAW,CAAC,SAAS,EAAE;wBACjC,aAAa,EAAE,UAAW,CAAC,gBAAgB,EAAE;qBAC9C,CAAC;iBACH,CAAC;SACH,CAAC,CACH,CAAC;QAEF,6FAA6F;QAC7F,UAAU,CAAC,YAAY,CAAC,GAAG,EAAE;YAC3B,IAAI,CAAC;gBACH,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC;YAC/D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,iEAAiE;gBACjE,MAAM,CAAC,IAAI,CAAC,gDAAgD,GAAG,EAAE,CAAC,CAAC;YACrE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,0BAA0B;IAC1B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,wDAAwD;IACxD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,WAAW,KAAK,cAAc,qBAAqB,CACvD,CAAC;IAEF,+EAA+E;IAC/E,6EAA6E;IAC7E,4EAA4E;IAC5E,KAAK,cAAc,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QACjD,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,KAAK;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CACT,gMAAgM,CACjM,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;IAC5C,2CAA2C;IAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ import type { PersistedMailCredentials } from "../cloud/mail-credential-store.js";
2
+ /**
3
+ * Inbound-mail port (Cogent Mail M2.3). Symmetric to the outbound {@link MailSender}:
4
+ * the fetch tool depends on THIS interface, not on imapflow, so it is unit-testable with a
5
+ * fake IMAP session and the IMAP library is swappable + loaded lazily (off the cold-start
6
+ * path). Following RemoteDataSource / Dependency_Injection
7
+ * (typescript-master-vault/concepts/RemoteDataSource.md, Dependency_Injection.md).
8
+ */
9
+ export interface MailSummary {
10
+ uid: number;
11
+ from: string;
12
+ subject: string;
13
+ date: string;
14
+ unread: boolean;
15
+ }
16
+ export interface SavedAttachment {
17
+ filename: string;
18
+ savedPath: string;
19
+ size: number;
20
+ }
21
+ export interface FetchedMail {
22
+ uid: number;
23
+ from: string;
24
+ subject: string;
25
+ date: string;
26
+ text: string;
27
+ attachments: SavedAttachment[];
28
+ }
29
+ export interface MailFetcher {
30
+ /** List messages (most recent first) as lightweight summaries — no bodies downloaded. */
31
+ list(opts?: {
32
+ unreadOnly?: boolean;
33
+ limit?: number;
34
+ }): Promise<MailSummary[]>;
35
+ /** Fetch one message by UID: text body + attachments saved to `downloadDir`. */
36
+ fetchOne(uid: number, downloadDir: string): Promise<FetchedMail>;
37
+ }
38
+ /** Raw envelope row as produced by the IMAP session (already parsed to plain data). */
39
+ export interface RawMessage {
40
+ uid: number;
41
+ from: string;
42
+ subject: string;
43
+ date: string;
44
+ unread: boolean;
45
+ }
46
+ /** Decoded message content as produced by the IMAP session (attachments in memory). */
47
+ export interface RawContent {
48
+ from: string;
49
+ subject: string;
50
+ date: string;
51
+ text: string;
52
+ attachments: {
53
+ filename: string;
54
+ content: Buffer;
55
+ }[];
56
+ }
57
+ /**
58
+ * The minimal IMAP surface the fetcher needs. Returning already-parsed plain data keeps the
59
+ * imapflow specifics behind {@link defaultImapSessionFactory}, so ImapflowMailFetcher's
60
+ * disk-saving + summary logic is unit-tested against a fake session.
61
+ */
62
+ export interface ImapSession {
63
+ list(unreadOnly: boolean): Promise<RawMessage[]>;
64
+ fetch(uid: number): Promise<RawContent>;
65
+ close(): Promise<void>;
66
+ }
67
+ export type ImapSessionFactory = (creds: PersistedMailCredentials) => Promise<ImapSession>;
68
+ /** In-memory fetcher: a fixed inbox. The test double the tool drives. */
69
+ export declare class InMemoryMailFetcher implements MailFetcher {
70
+ private readonly inbox;
71
+ constructor(inbox?: (RawMessage & {
72
+ text: string;
73
+ attachments: {
74
+ filename: string;
75
+ content: Buffer;
76
+ }[];
77
+ })[]);
78
+ list(opts?: {
79
+ unreadOnly?: boolean;
80
+ limit?: number;
81
+ }): Promise<MailSummary[]>;
82
+ fetchOne(uid: number, downloadDir: string): Promise<FetchedMail>;
83
+ }
84
+ /**
85
+ * Real IMAP fetcher. The imapflow session is created LAZILY (dynamic import) so imapflow never
86
+ * loads on the cold-start path — only when the agent actually fetches mail. `sessionFactory` is
87
+ * the injection seam for tests (default connects a real imapflow session).
88
+ */
89
+ export declare class ImapflowMailFetcher implements MailFetcher {
90
+ private readonly creds;
91
+ private readonly sessionFactory;
92
+ constructor(creds: PersistedMailCredentials, sessionFactory?: ImapSessionFactory);
93
+ list(opts?: {
94
+ unreadOnly?: boolean;
95
+ limit?: number;
96
+ }): Promise<MailSummary[]>;
97
+ fetchOne(uid: number, downloadDir: string): Promise<FetchedMail>;
98
+ }
99
+ /** A leaf MIME part reference extracted from an imapflow bodyStructure tree. */
100
+ export interface MimePartRef {
101
+ part: string;
102
+ type: string;
103
+ isText: boolean;
104
+ filename?: string;
105
+ }
106
+ /**
107
+ * Flatten an imapflow bodyStructure into its leaf parts. Attachment leaves carry a `filename`
108
+ * (from disposition or content-type params); text/plain leaves are marked `isText`. Multipart
109
+ * container nodes (those with `childNodes`) are recursed, not emitted.
110
+ */
111
+ export declare function flattenBodyStructure(node: unknown, acc?: MimePartRef[]): MimePartRef[];
112
+ //# sourceMappingURL=mail-fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-fetcher.d.ts","sourceRoot":"","sources":["../../src/mail/mail-fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ /** In-memory fetcher: a fixed inbox. The test double the tool drives. */
4
+ export class InMemoryMailFetcher {
5
+ inbox;
6
+ constructor(inbox = []) {
7
+ this.inbox = inbox;
8
+ }
9
+ async list(opts = {}) {
10
+ let rows = this.inbox.map(({ uid, from, subject, date, unread }) => ({ uid, from, subject, date, unread }));
11
+ if (opts.unreadOnly)
12
+ rows = rows.filter((m) => m.unread);
13
+ if (opts.limit && opts.limit > 0)
14
+ rows = rows.slice(0, opts.limit);
15
+ return rows;
16
+ }
17
+ async fetchOne(uid, downloadDir) {
18
+ const msg = this.inbox.find((m) => m.uid === uid);
19
+ if (!msg)
20
+ throw new Error(`no message with uid ${uid}`);
21
+ const saved = await saveAttachments(msg.attachments, downloadDir);
22
+ return { uid, from: msg.from, subject: msg.subject, date: msg.date, text: msg.text, attachments: saved };
23
+ }
24
+ }
25
+ /**
26
+ * Real IMAP fetcher. The imapflow session is created LAZILY (dynamic import) so imapflow never
27
+ * loads on the cold-start path — only when the agent actually fetches mail. `sessionFactory` is
28
+ * the injection seam for tests (default connects a real imapflow session).
29
+ */
30
+ export class ImapflowMailFetcher {
31
+ creds;
32
+ sessionFactory;
33
+ constructor(creds, sessionFactory = defaultImapSessionFactory) {
34
+ this.creds = creds;
35
+ this.sessionFactory = sessionFactory;
36
+ }
37
+ async list(opts = {}) {
38
+ const session = await this.sessionFactory(this.creds);
39
+ try {
40
+ let rows = await session.list(opts.unreadOnly ?? false);
41
+ if (opts.limit && opts.limit > 0)
42
+ rows = rows.slice(0, opts.limit);
43
+ return rows;
44
+ }
45
+ finally {
46
+ await session.close();
47
+ }
48
+ }
49
+ async fetchOne(uid, downloadDir) {
50
+ const session = await this.sessionFactory(this.creds);
51
+ try {
52
+ const c = await session.fetch(uid);
53
+ const saved = await saveAttachments(c.attachments, downloadDir);
54
+ return { uid, from: c.from, subject: c.subject, date: c.date, text: c.text, attachments: saved };
55
+ }
56
+ finally {
57
+ await session.close();
58
+ }
59
+ }
60
+ }
61
+ /** Write each in-memory attachment to `downloadDir` (created if needed), named by basename. */
62
+ async function saveAttachments(attachments, downloadDir) {
63
+ if (attachments.length === 0)
64
+ return [];
65
+ await fs.mkdir(downloadDir, { recursive: true });
66
+ const saved = [];
67
+ for (const a of attachments) {
68
+ const name = path.basename(a.filename) || "attachment";
69
+ const savedPath = path.join(downloadDir, name);
70
+ await fs.writeFile(savedPath, a.content);
71
+ saved.push({ filename: name, savedPath, size: a.content.length });
72
+ }
73
+ return saved;
74
+ }
75
+ /**
76
+ * Default imapflow session. Lazily imported via a variable specifier so tsc/esbuild never
77
+ * statically resolve or bundle imapflow — it loads from node_modules only when an agent fetches
78
+ * mail (off the cold-start path). The imapflow call shapes here are verified against the real
79
+ * mail box at the M2.8 live A→B E2E (the same "wiring proven at live E2E" seam used by
80
+ * NodemailerMailSender.defaultTransport); the disk-save + summary logic around it is unit-tested.
81
+ */
82
+ async function defaultImapSessionFactory(creds) {
83
+ const specifier = "imapflow";
84
+ const { ImapFlow } = (await import(specifier));
85
+ const client = new ImapFlow({
86
+ host: creds.imapHost,
87
+ port: creds.imapPort,
88
+ secure: creds.imapPort === 993,
89
+ auth: { user: creds.address, pass: creds.password },
90
+ logger: false,
91
+ });
92
+ await client.connect();
93
+ await client.mailboxOpen("INBOX");
94
+ return {
95
+ async list(unreadOnly) {
96
+ const criteria = unreadOnly ? { seen: false } : { all: true };
97
+ const rows = [];
98
+ for await (const msg of client.fetch(criteria, { uid: true, envelope: true, flags: true })) {
99
+ const env = msg.envelope ?? {};
100
+ rows.push({
101
+ uid: msg.uid,
102
+ from: env.from?.[0]?.address ?? "",
103
+ subject: env.subject ?? "",
104
+ date: env.date instanceof Date ? env.date.toISOString() : String(env.date ?? ""),
105
+ unread: !hasFlag(msg.flags, "\\Seen"),
106
+ });
107
+ }
108
+ return rows.reverse(); // newest first
109
+ },
110
+ async fetch(uid) {
111
+ const msg = await client.fetchOne(uid, { uid: true, envelope: true, bodyStructure: true }, { uid: true });
112
+ if (!msg)
113
+ throw new Error(`no message with uid ${uid}`);
114
+ const parts = flattenBodyStructure(msg.bodyStructure);
115
+ let text = "";
116
+ const attachments = [];
117
+ for (const p of parts) {
118
+ if (p.filename) {
119
+ const dl = await client.download(uid, p.part, { uid: true });
120
+ attachments.push({ filename: p.filename, content: await streamToBuffer(dl.content) });
121
+ }
122
+ else if (p.isText && !text) {
123
+ const dl = await client.download(uid, p.part, { uid: true });
124
+ text = (await streamToBuffer(dl.content)).toString("utf-8");
125
+ }
126
+ }
127
+ const env = msg.envelope ?? {};
128
+ return {
129
+ from: env.from?.[0]?.address ?? "",
130
+ subject: env.subject ?? "",
131
+ date: env.date instanceof Date ? env.date.toISOString() : String(env.date ?? ""),
132
+ text,
133
+ attachments,
134
+ };
135
+ },
136
+ async close() {
137
+ try {
138
+ await client.logout();
139
+ }
140
+ catch {
141
+ /* best-effort close */
142
+ }
143
+ },
144
+ };
145
+ }
146
+ /**
147
+ * Flatten an imapflow bodyStructure into its leaf parts. Attachment leaves carry a `filename`
148
+ * (from disposition or content-type params); text/plain leaves are marked `isText`. Multipart
149
+ * container nodes (those with `childNodes`) are recursed, not emitted.
150
+ */
151
+ export function flattenBodyStructure(node, acc = []) {
152
+ if (!node || typeof node !== "object")
153
+ return acc;
154
+ const n = node;
155
+ if (Array.isArray(n.childNodes) && n.childNodes.length > 0) {
156
+ for (const child of n.childNodes)
157
+ flattenBodyStructure(child, acc);
158
+ return acc;
159
+ }
160
+ const type = (n.type ?? "").toLowerCase();
161
+ const filename = n.dispositionParameters?.filename ?? n.parameters?.name;
162
+ const isAttachment = (n.disposition ?? "").toLowerCase() === "attachment" || Boolean(filename);
163
+ acc.push({
164
+ part: n.part ?? "1", // single-part messages have no `part`; imapflow addresses them as "1"
165
+ type,
166
+ isText: type === "text/plain" && !isAttachment,
167
+ filename: isAttachment ? filename : undefined,
168
+ });
169
+ return acc;
170
+ }
171
+ function hasFlag(flags, flag) {
172
+ if (flags instanceof Set)
173
+ return flags.has(flag);
174
+ if (Array.isArray(flags))
175
+ return flags.includes(flag);
176
+ return false;
177
+ }
178
+ async function streamToBuffer(stream) {
179
+ const chunks = [];
180
+ if (!stream)
181
+ return Buffer.alloc(0);
182
+ for await (const chunk of stream)
183
+ chunks.push(Buffer.from(chunk));
184
+ return Buffer.concat(chunks);
185
+ }
186
+ //# sourceMappingURL=mail-fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-fetcher.js","sourceRoot":"","sources":["../../src/mail/mail-fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { PersistedMailCredentials } from "../cloud/mail-credential-store.js";
2
+ /**
3
+ * Outbound-mail port (Cogent Mail M2.2). Following RemoteDataSource / Dependency_Injection
4
+ * (typescript-master-vault/concepts/RemoteDataSource.md, Dependency_Injection.md): the send
5
+ * tool depends on THIS interface, not on nodemailer, so it is unit-testable with an in-memory
6
+ * double and the SMTP library is swappable + loaded lazily (off the cold-start path).
7
+ */
8
+ export interface OutgoingMail {
9
+ from: string;
10
+ to: string[];
11
+ subject: string;
12
+ text: string;
13
+ attachments: {
14
+ filename: string;
15
+ content: Buffer;
16
+ }[];
17
+ }
18
+ export interface MailSender {
19
+ send(mail: OutgoingMail): Promise<{
20
+ messageId: string;
21
+ }>;
22
+ }
23
+ /** In-memory sender: records what was sent. The test double the tool/service drives. */
24
+ export declare class InMemoryMailSender implements MailSender {
25
+ readonly sent: OutgoingMail[];
26
+ send(mail: OutgoingMail): Promise<{
27
+ messageId: string;
28
+ }>;
29
+ }
30
+ /**
31
+ * Real SMTP sender. nodemailer is imported LAZILY (dynamic import) so it never loads on
32
+ * the bridge's cold-start path — only when the agent actually sends mail. `transportFactory`
33
+ * is an injection seam for tests (default builds a real nodemailer SMTP transport from the creds).
34
+ */
35
+ export declare class NodemailerMailSender implements MailSender {
36
+ private readonly creds;
37
+ private readonly transportFactory?;
38
+ constructor(creds: PersistedMailCredentials, transportFactory?: (() => Promise<{
39
+ sendMail(opts: unknown): Promise<{
40
+ messageId?: string;
41
+ }>;
42
+ }>) | undefined);
43
+ send(mail: OutgoingMail): Promise<{
44
+ messageId: string;
45
+ }>;
46
+ private defaultTransport;
47
+ }
48
+ /**
49
+ * Compose and send a mail from the agent's mailbox: reads each attachment from its local path
50
+ * (streaming the bytes into a Buffer), builds the {@link OutgoingMail}, and sends via the port.
51
+ * A missing/unreadable attachment path fails loud (the caller surfaces it as errorResult) rather
52
+ * than silently dropping the file. Returns the message id + the sending address.
53
+ */
54
+ export declare function buildAndSendMail(sender: MailSender, creds: PersistedMailCredentials, params: {
55
+ to: string[];
56
+ subject: string;
57
+ text: string;
58
+ attachmentPaths?: string[];
59
+ }): Promise<{
60
+ messageId: string;
61
+ from: string;
62
+ to: string[];
63
+ }>;
64
+ //# sourceMappingURL=mail-sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-sender.d.ts","sourceRoot":"","sources":["../../src/mail/mail-sender.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAElF;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACtD;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1D;AAED,wFAAwF;AACxF,qBAAa,kBAAmB,YAAW,UAAU;IACnD,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,CAAM;IAC7B,IAAI,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAI/D;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,UAAU;IAEnD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBADjB,KAAK,EAAE,wBAAwB,EAC/B,gBAAgB,CAAC,GAAE,MAAM,OAAO,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;YAAE,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,aAAA;IAG3G,IAAI,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;YAYhD,gBAAgB;CAY/B;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,wBAAwB,EAC/B,MAAM,EAAE;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAClF,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAc5D"}