UNPKG

@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.

195 lines • 11.3 kB
import { getBackend, isCloudMode } from "../backend/index.js"; import { getConfig } from "../config.js"; import { SERVER_VERSION } from "../constants.js"; import { getLastNudge } from "../backend/npm-update-check.js"; import { successResult, errorResult } from "../errors.js"; import { logger } from "../logger.js"; import { autoRelay } from "../services/auto-relay.js"; import { getPresence } from "../services/peer-presence.js"; export function registerHealthCheckTool(server) { server.registerTool("cogent_health_check", { title: "Health Check", description: "Diagnose the bridge's operational status. Checks state file accessibility, " + "lock mechanism, and Claude CLI availability. Returns per-check pass/fail with details.", inputSchema: {}, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async () => { try { const backend = getBackend(); const result = await backend.checkHealth(); // Read live WS transport state from the startup-time singleton. // Dynamic import avoids a circular dep with startup.ts (which itself // imports backend code transitively). In local mode or when startup // hasn't run, defaults are wsConnected=false / wsLastFrameAt=null -- // the field is always present so consumers don't need a mode switch. let wsConnected = false; let delivery = null; let wsLastFrameAt = null; let wsLastFrameAtMs = null; try { const startup = await import("../startup.js"); if (startup.cloudWsClient) { wsConnected = startup.cloudWsClient.isConnected(); delivery = startup.cloudWsClient.getDeliveryDiagnostics?.() ?? null; wsLastFrameAt = startup.cloudWsClient.getLastFrameAt(); wsLastFrameAtMs = startup.cloudWsClient.getLastFrameAtMs(); } } catch (err) { // Test harness or local-only mode -- defaults are correct. Log at // debug so a future regression (syntax error in startup.ts, circular // dep, torn singleton) is observable when COGENT_LOG_LEVEL=debug. // Audit L1. logger.debug(`health-check: startup module unavailable: ${err instanceof Error ? err.message : String(err)}`); } const cloud = isCloudMode(); // wsHealth: cloud-only enum derived from wsConnected + wsAgeMs vs COGENT_WS_STALE_MS. // Four states (3.2.2): "fresh" (connected, recent frame), "stale" (connected, no // frame within threshold — see 3.1.10 keepalive-pong refresh), "reconnecting" // (socket momentarily down but last frame was recent, i.e. an in-progress // auto-reconnect cycle — bridge keepalive cycles every ~5-20min on idle channels // and each cycle takes 1-4s; pre-3.2.2 reported these as "disconnected" which // alarmed operators on a healthy idle channel), and "disconnected" (socket down // and last frame older than threshold, i.e. extended outage). Null age while // connected => "fresh" (just-connected grace). let wsHealth = "fresh"; if (cloud) { const threshold = getConfig().COGENT_WS_STALE_MS; const ageMs = wsLastFrameAtMs === null ? null : Date.now() - wsLastFrameAtMs; if (!wsConnected) { // Socket-down + recent frame = transient reconnect, not a real outage. // Same threshold as fresh/stale boundary so the metric stays internally // consistent (no second tunable env var). if (ageMs !== null && ageMs <= threshold) { wsHealth = "reconnecting"; } else { wsHealth = "disconnected"; } } else if (ageMs !== null && ageMs > threshold) { wsHealth = "stale"; } else { wsHealth = "fresh"; } } // VER-02: lazy lookup of the upstream relay version. Cloud-only — // HttpBackend implements getRelayVersion (delegates to the 60s TTL // cache); FileBackend omits it. On fetch failure the cache returns // null and we keep null here; the rest of the health response stays // intact. Optional-chained so a backend without the method (e.g., // FileBackend) cannot break the tool. let relayVersion = null; if (cloud && typeof backend.getRelayVersion === "function") { try { relayVersion = (await backend.getRelayVersion()) ?? null; } catch (err) { // Defense in depth — the cache module already swallows fetch // errors and returns null, but if a future backend impl throws // we still want health-check to succeed. logger.debug(`health-check: getRelayVersion threw: ${err instanceof Error ? err.message : String(err)}`); relayVersion = null; } } // Surface the running client version and, if the startup npm check found a // newer release, the same update nudge — so the agent shows the user they're // on a stale build (the recurring "/cogent map is out of date" pain). The nudge // is computed once at startup (best-effort, never blocks); null when current. const updateAvailable = getLastNudge(); /** * 🔴 `healthy` USED TO MEAN "THE RELAY IS UP" (http-backend: `resp.status === "ok"`). * It never described THIS BRIDGE, so an agent with no delivery path at all still answered * `healthy: true`, was listed in the roster and looked live. Reported by marvin-mobile on * 2026-09-06 after losing a day to it. * * `wsConnected: false` alone is NOT unreachable — the poll fallback delivers, and that is * how the reporter's own messages were arriving. Marking a working degraded mode "broken" * would fire on every ordinary reconnect. The condition is: is ANY path delivering? */ const relayHealthy = result.healthy !== false; let deliveryPath = "unknown"; if (cloud && delivery) { deliveryPath = wsConnected ? "websocket" // A poll that has not completed a cycle yet is UNKNOWN, not failed — do not alarm on it. : delivery.pollActive && !delivery.lastPollError ? "poll" : "none"; } else if (cloud && wsConnected) { deliveryPath = "websocket"; } const registered = autoRelay.getDiagnostics().registered; // Only a REGISTERED cloud peer has anything addressed to it; an unregistered bridge with no // socket is idle, not broken. const deliveryBroken = cloud && registered && deliveryPath === "none"; const unhealthyReason = deliveryBroken ? `registered as a cloud peer but NO delivery path is working (websocket down${delivery?.lastWsError ? `: ${delivery.lastWsError}` : ""}; poll ${delivery?.lastPollError ? `failing: ${delivery.lastPollError}` : "inactive"}) — ` + `messages addressed to this peer cannot reach it` : null; const enriched = { ...JSON.parse(JSON.stringify(result)), healthy: relayHealthy && !deliveryBroken, ...(unhealthyReason ? { unhealthyReason } : {}), clientVersion: SERVER_VERSION, ...(updateAvailable ? { updateAvailable } : {}), runtimeMode: cloud ? "cloud" : "local", // Field placement: mode -> transport -> autoRelay reads sensibly // in JSON output (operational layers from outermost to innermost). transport: { // wsApplicable first so consumers see the gate before the gated // values; existing two fields keep their relative order; wsAgeMs // last (newest, least likely to be relied on by existing // consumers). Audit L5 + L2. wsApplicable: cloud, wsConnected, wsLastFrameAt, wsAgeMs: wsLastFrameAtMs === null ? null : Date.now() - wsLastFrameAtMs, // wsHealth: cloud-only by design — local backends have no WS to assess. // relayVersion: cloud-only (VER-02). Populated from a 60s TTL cache // on HttpBackend; null when the /api/health fetch fails. Keep the // key cloud-gated for shape consistency with wsHealth (local mode // never has an upstream relay version to report). ...(cloud ? { wsHealth, relayVersion, deliveryPath, lastWsError: delivery?.lastWsError ?? null } : {}), }, autoRelay: autoRelay.getDiagnostics(), // PRESENCE — the agent's own view of whether it is IN its channel, so it can // answer "am I reachable?" without inferring it from transport internals. // "online" registered · "offline" owns a peer but is not registered (nobody can // reach it) · "standby" another live bridge serves this peer, so THIS process is not // registered (servedBy names it) · "deferred" never joined · "local" no relay. // services/peer-presence.ts carries the vocabulary and how each state arises. presence: (() => { const p = getPresence(); if (!p) { // Evaluated once at startup, fire-and-forget. Null means that has not // completed — report the uncertainty rather than guessing a state. return { state: "unknown", detail: "presence has not been evaluated yet" }; } return { state: p.state, restored: p.restored, detail: p.detail, ...("peerId" in p ? { peerId: p.peerId } : {}), ...("servedBy" in p ? { servedBy: p.servedBy } : {}), }; })(), }; return successResult(enriched); } catch (err) { logger.error("health-check failed", { error: err }); return errorResult(err); } }); } //# sourceMappingURL=health-check.js.map