@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.
99 lines • 5.06 kB
JavaScript
import { z } from "zod";
import { getBackend, isCloudDeferred } from "../backend/index.js";
import { getConfig } from "../config.js";
import { successResult, errorResult } from "../errors.js";
import { logger } from "../logger.js";
import { heartbeat } from "../services/heartbeat.js";
import { clearMailCredentials } from "../cloud/mail-credential-store.js";
import { loadCredentials, saveCredentials } from "../cloud/credential-store.js";
export function registerDeregisterPeerTool(server) {
server.registerTool("cogent_deregister_peer", {
title: "Deregister Peer",
description: "Remove a previously registered peer from the bridge. " +
"The peer will no longer be reachable for messaging.",
inputSchema: {
peerId: z
.string()
.describe("Peer ID to deregister, e.g. 'backend'"),
},
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: true,
openWorldHint: false,
},
}, async ({ peerId }) => {
try {
// SECURITY: an unjoined cloud agent (deferred FileBackend placeholder)
// must not touch the host-global cogent-state.json — deregisterPeer there
// is both an existence oracle (the `removed` boolean) and a destructive
// DELETE of ANOTHER channel's peer. Refuse; it belongs to no channel.
if (isCloudDeferred(getConfig().COGENT_ENDPOINT)) {
return successResult({
success: false,
notJoined: true,
removed: false,
message: "Not connected to a channel yet — call cogent_join_session (or cogent_register_peer) first. Nothing to deregister.",
});
}
const backend = getBackend();
// Read the ownership proof BEFORE deleting — the block below clears it from the stored
// credential on success, so loading it afterwards would always come back empty.
let ownershipProof;
try {
ownershipProof = (await loadCredentials())?.peerSecret;
}
catch {
/* no stored credential — the current token must prove ownership on its own */
}
const { removed, mailboxDeprovisioned } = await backend.deregisterPeer(peerId, ownershipProof);
if (removed)
heartbeat.stop();
// Cogent Mail F3: if the relay confirmed our Team mailbox was reaped, the locally-stored
// creds are now dead — clear them so a stale password never lingers (a returning agent
// re-provisions fresh on the next register). Best-effort: a cleanup failure must not fail
// the deregister the user asked for.
if (mailboxDeprovisioned) {
try {
await clearMailCredentials();
logger.info("cleared local mail credentials after mailbox deprovision", { peerId });
}
catch (err) {
logger.warn("failed to clear local mail credentials after deprovision", { error: err });
}
}
// 🔴 CLEAR THE peerId FROM THE STORED CREDENTIAL — the CONSENT SIGNAL.
// Cold-start rejoin (services/cold-start-rejoin.ts) restores a registration at
// startup when the credential file names a peer. Leaving the peerId here after a
// deliberate deregister would make the next bridge start put this agent straight
// back into the channel the operator just removed it from. The rest of the
// credential (endpoint, sessionId, token) is KEPT: the channel membership is
// still valid and cogent_register_peer must keep working without a re-join.
// Best-effort — a cleanup failure must not fail the deregister that succeeded.
if (removed) {
try {
const creds = await loadCredentials();
if (creds?.peerId === peerId) {
const { peerId: _dropped, peerSecret: _secret, ...rest } = creds;
await saveCredentials({ ...rest, savedAt: new Date().toISOString() });
logger.info("cleared stored peerId after deregister", { peerId });
}
}
catch (err) {
logger.warn("failed to clear stored peerId after deregister", { error: err });
}
}
return successResult({
success: removed,
message: removed
? `Peer '${peerId}' deregistered`
: `Peer '${peerId}' was not registered`,
});
}
catch (err) {
logger.error("deregister-peer failed", { error: err });
return errorResult(err);
}
});
}
//# sourceMappingURL=deregister-peer.js.map