@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.
135 lines • 6.47 kB
JavaScript
import fs from "node:fs/promises";
import path from "node:path";
import { execFile } from "node:child_process";
import { getConfig } from "../config.js";
import { SERVER_VERSION } from "../constants.js";
import { probeSandboxStatus } from "./codex-preflight.js";
/* ------------------------------------------------------------------ */
/* Derive paths from config at call time (not module load time) */
/* ------------------------------------------------------------------ */
function getStatePath() {
return path.join(getConfig().COGENT_STATE_PATH, "cogent-state.json");
}
/* ------------------------------------------------------------------ */
/* Sub-checks */
/* ------------------------------------------------------------------ */
/** HLTH-01: Check state file accessibility. */
async function checkStateFile() {
const statePath = getStatePath();
const dir = path.dirname(statePath);
try {
await fs.access(dir, fs.constants.R_OK | fs.constants.W_OK);
}
catch {
return { ok: false, message: `State directory not accessible: ${dir}` };
}
try {
const raw = await fs.readFile(statePath, "utf-8");
JSON.parse(raw);
return { ok: true, message: "State file readable and valid JSON" };
}
catch (err) {
if (err.code === "ENOENT") {
return { ok: true, message: "State directory writable (no state file yet)" };
}
if (err instanceof SyntaxError) {
return { ok: false, message: "State file exists but contains invalid JSON" };
}
return { ok: false, message: `State file error: ${err.message}` };
}
}
/** HLTH-02: Check lock mechanism with a separate health-check lock path. */
async function checkLockMechanism() {
const healthLockPath = getStatePath() + ".health-lock";
try {
await fs.writeFile(healthLockPath, String(process.pid), { flag: "wx" });
try {
await fs.unlink(healthLockPath);
}
catch {
// Cleanup failure is non-fatal
}
return { ok: true, message: "Lock acquire/release cycle succeeded" };
}
catch (err) {
if (err.code === "EEXIST") {
return { ok: false, message: "Health check lock file exists unexpectedly" };
}
return { ok: false, message: `Lock mechanism error: ${err.message}` };
}
}
/** HLTH-03: Check Claude CLI availability. */
function checkClaudeCli() {
const claudePath = getConfig().COGENT_CLAUDE_PATH;
return new Promise((resolve) => {
execFile(claudePath, ["--version"], { timeout: 5000 }, (error, stdout) => {
if (error) {
resolve({ ok: false, message: `Claude CLI not found at '${claudePath}'` });
return;
}
resolve({ ok: true, message: "Claude CLI found", version: (stdout || "").trim() });
});
});
}
/** HLTH-04: Can the host initialize the Codex OS sandbox? (codex platform only.) */
export async function checkCodexSandbox() {
const config = getConfig();
if (config.COGENT_PLATFORM !== "codex") {
return { ok: true, message: "n/a (platform is not codex)" };
}
const probe = await probeSandboxStatus(config);
if (probe.status === "blocked") {
if (config.COGENT_CODEX_SANDBOX_FALLBACK) {
// 🔴 SCOPE THE CLAIM. This used to end "...so codex runs unsandboxed", which reads as a
// statement about the reader's own codex session. It is not, and cannot be: the fallback
// calls setSandboxOverride("bypass") (startup.ts), which only reaches sandboxArgs() in
// codex-cli.ts, whose single non-test caller is execCodex via exec-remote.ts — i.e. the
// `codex exec resume` subprocesses COGENT spawns to wake an agent. An already-running
// interactive codex session was launched separately with its own sandbox/approval profile
// and is untouched by this setting.
//
// Reported 2026-09-17 by an agent that read this line, concluded its own session should be
// unsandboxed, and then had to explain why bwrap was still failing — the message sent it
// looking in the wrong place. Same family as relay-fabricates-success: a field that reports
// what Cogent CONFIGURED, not what the reader's session will DO.
return {
ok: true,
message: `Sandbox blocked (${probe.detail}) — auto-bypass is ON, so codex sessions COGENT WAKES ` +
`run unsandboxed. This does NOT change an already-running interactive codex session: ` +
`that keeps the sandbox/approval profile it was launched with, and on this host its ` +
`bwrap-backed modes will still fail. Relaunch it with ` +
`--dangerously-bypass-approvals-and-sandbox, or enable unprivileged userns, to fix that.`,
};
}
return { ok: false, message: `Sandbox blocked: ${probe.detail}. Codex can't edit/test — set COGENT_CODEX_SANDBOX_FALLBACK=1, COGENT_CODEX_SANDBOX=bypass, or enable unprivileged userns` };
}
if (probe.status === "unknown") {
return { ok: true, message: `Sandbox capability unknown: ${probe.detail}` };
}
return { ok: true, message: probe.detail };
}
/* ------------------------------------------------------------------ */
/* Public API */
/* ------------------------------------------------------------------ */
/** Run all health checks and return a comprehensive result. */
export async function checkHealth() {
const config = getConfig();
// Run all checks (not short-circuiting)
const [stateFile, lockMechanism, claudeCli, codexSandbox] = await Promise.all([
checkStateFile(),
checkLockMechanism(),
checkClaudeCli(),
checkCodexSandbox(),
]);
const checks = { stateFile, lockMechanism, claudeCli, codexSandbox };
const healthy = Object.values(checks).every((c) => c.ok);
return {
healthy,
mcpServerVersion: SERVER_VERSION,
statePath: path.join(config.COGENT_STATE_PATH, "cogent-state.json"),
claudePath: config.COGENT_CLAUDE_PATH,
checks,
timestamp: new Date().toISOString(),
};
}
//# sourceMappingURL=health-check.js.map