@essentialai/cogent-bridge
Version:
Cogent Bridge — cross-agent comms for Claude Code, OpenAI Codex and Slack. Codex users: install with `curl -fsSL https://cogent.tools/install.sh | sh`, then start with `cogent-codex` for real-time peer wake.
83 lines • 5.01 kB
JavaScript
import { successResult, errorResult, BridgeError, BridgeErrorCode } from "../errors.js";
import { loadCredentials } from "../cloud/credential-store.js";
import { loadMailCredentials, saveMailCredentials, MAIL_DEFAULT_HOST, } from "../cloud/mail-credential-store.js";
/** Total budget for the relay round-trip. */
const ROTATE_TIMEOUT_MS = 8000;
/**
* cogent_rotate_mail_creds — self-service mailbox password rotation (Cogent Mail M2.4).
*
* Re-keys THIS agent's Team mailbox: the bridge asks the relay (authenticated by the per-cwd cloud
* session token) to rotate on the mail server; the relay derives orgScope + channel label from the
* session (never client input) so the box is targeted deterministically. On success the fresh
* password is returned ONCE and written to the per-cwd 0600 mail-credential store, so subsequent
* cogent_send_mail / cogent_fetch_mail keep working. Use it if a mailbox password may be compromised.
*
* Cloud + Team only: it needs cloud credentials (endpoint/session/token/peerId) and a CP-provisioned
* mailbox. A free/local session gets a clear "rotation isn't available for this channel" error.
*/
export function registerRotateMailCredsTool(server) {
server.registerTool("cogent_rotate_mail_creds", {
title: "Rotate this agent's mailbox password",
description: "Rotate (re-key) this agent's Team mailbox password on the mail server and update the local " +
"credential store, so cogent_send_mail / cogent_fetch_mail keep working with the fresh secret. " +
"Use it if the mailbox password may be compromised. Team channels only.",
inputSchema: {},
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
}, async () => {
try {
const creds = await loadCredentials();
if (!creds || !creds.endpoint || !creds.sessionId || !creds.token) {
throw new BridgeError(BridgeErrorCode.INVALID_INPUT, "Not registered in cloud mode", "Rotation applies to a cloud Team channel — register the peer first");
}
if (!creds.peerId) {
throw new BridgeError(BridgeErrorCode.INVALID_INPUT, "Cannot identify this peer", "Re-register the peer so its peerId is stored, then rotate");
}
const url = `${creds.endpoint.replace(/\/+$/, "")}/api/sessions/${encodeURIComponent(creds.sessionId)}` +
`/peers/${encodeURIComponent(creds.peerId)}/mail/rotate`;
let res;
try {
res = await fetch(url, {
method: "POST",
headers: { "content-type": "application/json", authorization: `Bearer ${creds.token}` },
body: "{}",
signal: AbortSignal.timeout(ROTATE_TIMEOUT_MS),
});
}
catch {
throw new BridgeError(BridgeErrorCode.NETWORK_TIMEOUT, "Could not reach the relay to rotate the mailbox", "Check connectivity and try again");
}
if (!res.ok) {
// The relay maps a non-Team / no-rotator channel to a 400 with a clear message.
const detail = await res.text().catch(() => "");
throw new BridgeError(BridgeErrorCode.INVALID_INPUT, `Mailbox rotation was rejected (HTTP ${res.status})`, detail.slice(0, 200) || "Rotation applies to Team channels with a provisioned mailbox");
}
const data = (await res.json().catch(() => null));
if (!data || data.success !== true) {
throw new BridgeError(BridgeErrorCode.NETWORK_TIMEOUT, "Mailbox rotation failed", "The relay returned an unexpected response");
}
if (!data.rotated) {
// Clean "nothing to rotate" (no mailbox) — do NOT touch the local creds.
return successResult({ rotated: false, reason: data.reason ?? "no_mailbox" });
}
if (!data.address || !data.password) {
throw new BridgeError(BridgeErrorCode.NETWORK_TIMEOUT, "Rotation returned no new password", "Try again; the mailbox password was not updated locally");
}
// Persist the fresh secret, preserving the existing host/port config where present.
const existing = await loadMailCredentials();
await saveMailCredentials({
address: data.address,
password: data.password,
imapHost: existing?.imapHost ?? MAIL_DEFAULT_HOST,
imapPort: existing?.imapPort ?? 993,
smtpHost: existing?.smtpHost ?? MAIL_DEFAULT_HOST,
smtpPort: existing?.smtpPort ?? 465,
savedAt: new Date().toISOString(),
});
return successResult({ rotated: true, address: data.address });
}
catch (err) {
return errorResult(err);
}
});
}
//# sourceMappingURL=rotate-mail-creds.js.map